1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/log2.h>
19
20#include "xfs.h"
21#include "xfs_fs.h"
22#include "xfs_types.h"
23#include "xfs_bit.h"
24#include "xfs_log.h"
25#include "xfs_inum.h"
26#include "xfs_trans.h"
27#include "xfs_trans_priv.h"
28#include "xfs_sb.h"
29#include "xfs_ag.h"
30#include "xfs_dir2.h"
31#include "xfs_dmapi.h"
32#include "xfs_mount.h"
33#include "xfs_bmap_btree.h"
34#include "xfs_alloc_btree.h"
35#include "xfs_ialloc_btree.h"
36#include "xfs_dir2_sf.h"
37#include "xfs_attr_sf.h"
38#include "xfs_dinode.h"
39#include "xfs_inode.h"
40#include "xfs_buf_item.h"
41#include "xfs_inode_item.h"
42#include "xfs_btree.h"
43#include "xfs_btree_trace.h"
44#include "xfs_alloc.h"
45#include "xfs_ialloc.h"
46#include "xfs_bmap.h"
47#include "xfs_rw.h"
48#include "xfs_error.h"
49#include "xfs_utils.h"
50#include "xfs_dir2_trace.h"
51#include "xfs_quota.h"
52#include "xfs_filestream.h"
53#include "xfs_vnodeops.h"
54
55kmem_zone_t *xfs_ifork_zone;
56kmem_zone_t *xfs_inode_zone;
57
58
59
60
61
62#define XFS_ITRUNC_MAX_EXTENTS 2
63
64STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *);
65STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int);
66STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int);
67STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);
68
69#ifdef DEBUG
70
71
72
73
74STATIC void
75xfs_validate_extents(
76 xfs_ifork_t *ifp,
77 int nrecs,
78 xfs_exntfmt_t fmt)
79{
80 xfs_bmbt_irec_t irec;
81 xfs_bmbt_rec_host_t rec;
82 int i;
83
84 for (i = 0; i < nrecs; i++) {
85 xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
86 rec.l0 = get_unaligned(&ep->l0);
87 rec.l1 = get_unaligned(&ep->l1);
88 xfs_bmbt_get_all(&rec, &irec);
89 if (fmt == XFS_EXTFMT_NOSTATE)
90 ASSERT(irec.br_state == XFS_EXT_NORM);
91 }
92}
93#else
94#define xfs_validate_extents(ifp, nrecs, fmt)
95#endif
96
97
98
99
100
101#if defined(DEBUG)
102void
103xfs_inobp_check(
104 xfs_mount_t *mp,
105 xfs_buf_t *bp)
106{
107 int i;
108 int j;
109 xfs_dinode_t *dip;
110
111 j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;
112
113 for (i = 0; i < j; i++) {
114 dip = (xfs_dinode_t *)xfs_buf_offset(bp,
115 i * mp->m_sb.sb_inodesize);
116 if (!dip->di_next_unlinked) {
117 xfs_fs_cmn_err(CE_ALERT, mp,
118 "Detected a bogus zero next_unlinked field in incore inode buffer 0x%p. About to pop an ASSERT.",
119 bp);
120 ASSERT(dip->di_next_unlinked);
121 }
122 }
123}
124#endif
125
126
127
128
129
130
131STATIC int
132xfs_imap_to_bp(
133 xfs_mount_t *mp,
134 xfs_trans_t *tp,
135 struct xfs_imap *imap,
136 xfs_buf_t **bpp,
137 uint buf_flags,
138 uint iget_flags)
139{
140 int error;
141 int i;
142 int ni;
143 xfs_buf_t *bp;
144
145 error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
146 (int)imap->im_len, buf_flags, &bp);
147 if (error) {
148 if (error != EAGAIN) {
149 cmn_err(CE_WARN,
150 "xfs_imap_to_bp: xfs_trans_read_buf()returned "
151 "an error %d on %s. Returning error.",
152 error, mp->m_fsname);
153 } else {
154 ASSERT(buf_flags & XFS_BUF_TRYLOCK);
155 }
156 return error;
157 }
158
159
160
161
162
163#ifdef DEBUG
164 ni = BBTOB(imap->im_len) >> mp->m_sb.sb_inodelog;
165#else
166 ni = 1;
167#endif
168
169 for (i = 0; i < ni; i++) {
170 int di_ok;
171 xfs_dinode_t *dip;
172
173 dip = (xfs_dinode_t *)xfs_buf_offset(bp,
174 (i << mp->m_sb.sb_inodelog));
175 di_ok = be16_to_cpu(dip->di_magic) == XFS_DINODE_MAGIC &&
176 XFS_DINODE_GOOD_VERSION(dip->di_version);
177 if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
178 XFS_ERRTAG_ITOBP_INOTOBP,
179 XFS_RANDOM_ITOBP_INOTOBP))) {
180 if (iget_flags & XFS_IGET_BULKSTAT) {
181 xfs_trans_brelse(tp, bp);
182 return XFS_ERROR(EINVAL);
183 }
184 XFS_CORRUPTION_ERROR("xfs_imap_to_bp",
185 XFS_ERRLEVEL_HIGH, mp, dip);
186#ifdef DEBUG
187 cmn_err(CE_PANIC,
188 "Device %s - bad inode magic/vsn "
189 "daddr %lld #%d (magic=%x)",
190 XFS_BUFTARG_NAME(mp->m_ddev_targp),
191 (unsigned long long)imap->im_blkno, i,
192 be16_to_cpu(dip->di_magic));
193#endif
194 xfs_trans_brelse(tp, bp);
195 return XFS_ERROR(EFSCORRUPTED);
196 }
197 }
198
199 xfs_inobp_check(mp, bp);
200
201
202
203
204 XFS_BUF_SET_VTYPE(bp, B_FS_INO);
205
206 *bpp = bp;
207 return 0;
208}
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223int
224xfs_inotobp(
225 xfs_mount_t *mp,
226 xfs_trans_t *tp,
227 xfs_ino_t ino,
228 xfs_dinode_t **dipp,
229 xfs_buf_t **bpp,
230 int *offset,
231 uint imap_flags)
232{
233 struct xfs_imap imap;
234 xfs_buf_t *bp;
235 int error;
236
237 imap.im_blkno = 0;
238 error = xfs_imap(mp, tp, ino, &imap, imap_flags);
239 if (error)
240 return error;
241
242 error = xfs_imap_to_bp(mp, tp, &imap, &bp, XFS_BUF_LOCK, imap_flags);
243 if (error)
244 return error;
245
246 *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset);
247 *bpp = bp;
248 *offset = imap.im_boffset;
249 return 0;
250}
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269int
270xfs_itobp(
271 xfs_mount_t *mp,
272 xfs_trans_t *tp,
273 xfs_inode_t *ip,
274 xfs_dinode_t **dipp,
275 xfs_buf_t **bpp,
276 uint buf_flags)
277{
278 xfs_buf_t *bp;
279 int error;
280
281 ASSERT(ip->i_imap.im_blkno != 0);
282
283 error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp, buf_flags, 0);
284 if (error)
285 return error;
286
287 if (!bp) {
288 ASSERT(buf_flags & XFS_BUF_TRYLOCK);
289 ASSERT(tp == NULL);
290 *bpp = NULL;
291 return EAGAIN;
292 }
293
294 *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
295 *bpp = bp;
296 return 0;
297}
298
299
300
301
302
303
304
305
306
307
308STATIC int
309xfs_iformat(
310 xfs_inode_t *ip,
311 xfs_dinode_t *dip)
312{
313 xfs_attr_shortform_t *atp;
314 int size;
315 int error;
316 xfs_fsize_t di_size;
317 ip->i_df.if_ext_max =
318 XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
319 error = 0;
320
321 if (unlikely(be32_to_cpu(dip->di_nextents) +
322 be16_to_cpu(dip->di_anextents) >
323 be64_to_cpu(dip->di_nblocks))) {
324 xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
325 "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.",
326 (unsigned long long)ip->i_ino,
327 (int)(be32_to_cpu(dip->di_nextents) +
328 be16_to_cpu(dip->di_anextents)),
329 (unsigned long long)
330 be64_to_cpu(dip->di_nblocks));
331 XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW,
332 ip->i_mount, dip);
333 return XFS_ERROR(EFSCORRUPTED);
334 }
335
336 if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) {
337 xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
338 "corrupt dinode %Lu, forkoff = 0x%x.",
339 (unsigned long long)ip->i_ino,
340 dip->di_forkoff);
341 XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW,
342 ip->i_mount, dip);
343 return XFS_ERROR(EFSCORRUPTED);
344 }
345
346 if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) &&
347 !ip->i_mount->m_rtdev_targp)) {
348 xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
349 "corrupt dinode %Lu, has realtime flag set.",
350 ip->i_ino);
351 XFS_CORRUPTION_ERROR("xfs_iformat(realtime)",
352 XFS_ERRLEVEL_LOW, ip->i_mount, dip);
353 return XFS_ERROR(EFSCORRUPTED);
354 }
355
356 switch (ip->i_d.di_mode & S_IFMT) {
357 case S_IFIFO:
358 case S_IFCHR:
359 case S_IFBLK:
360 case S_IFSOCK:
361 if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) {
362 XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW,
363 ip->i_mount, dip);
364 return XFS_ERROR(EFSCORRUPTED);
365 }
366 ip->i_d.di_size = 0;
367 ip->i_size = 0;
368 ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip);
369 break;
370
371 case S_IFREG:
372 case S_IFLNK:
373 case S_IFDIR:
374 switch (dip->di_format) {
375 case XFS_DINODE_FMT_LOCAL:
376
377
378
379 if (unlikely((be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFREG)) {
380 xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
381 "corrupt inode %Lu "
382 "(local format for regular file).",
383 (unsigned long long) ip->i_ino);
384 XFS_CORRUPTION_ERROR("xfs_iformat(4)",
385 XFS_ERRLEVEL_LOW,
386 ip->i_mount, dip);
387 return XFS_ERROR(EFSCORRUPTED);
388 }
389
390 di_size = be64_to_cpu(dip->di_size);
391 if (unlikely(di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) {
392 xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
393 "corrupt inode %Lu "
394 "(bad size %Ld for local inode).",
395 (unsigned long long) ip->i_ino,
396 (long long) di_size);
397 XFS_CORRUPTION_ERROR("xfs_iformat(5)",
398 XFS_ERRLEVEL_LOW,
399 ip->i_mount, dip);
400 return XFS_ERROR(EFSCORRUPTED);
401 }
402
403 size = (int)di_size;
404 error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size);
405 break;
406 case XFS_DINODE_FMT_EXTENTS:
407 error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK);
408 break;
409 case XFS_DINODE_FMT_BTREE:
410 error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
411 break;
412 default:
413 XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW,
414 ip->i_mount);
415 return XFS_ERROR(EFSCORRUPTED);
416 }
417 break;
418
419 default:
420 XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount);
421 return XFS_ERROR(EFSCORRUPTED);
422 }
423 if (error) {
424 return error;
425 }
426 if (!XFS_DFORK_Q(dip))
427 return 0;
428 ASSERT(ip->i_afp == NULL);
429 ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
430 ip->i_afp->if_ext_max =
431 XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
432 switch (dip->di_aformat) {
433 case XFS_DINODE_FMT_LOCAL:
434 atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
435 size = be16_to_cpu(atp->hdr.totsize);
436
437 if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) {
438 xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
439 "corrupt inode %Lu "
440 "(bad attr fork size %Ld).",
441 (unsigned long long) ip->i_ino,
442 (long long) size);
443 XFS_CORRUPTION_ERROR("xfs_iformat(8)",
444 XFS_ERRLEVEL_LOW,
445 ip->i_mount, dip);
446 return XFS_ERROR(EFSCORRUPTED);
447 }
448
449 error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size);
450 break;
451 case XFS_DINODE_FMT_EXTENTS:
452 error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK);
453 break;
454 case XFS_DINODE_FMT_BTREE:
455 error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK);
456 break;
457 default:
458 error = XFS_ERROR(EFSCORRUPTED);
459 break;
460 }
461 if (error) {
462 kmem_zone_free(xfs_ifork_zone, ip->i_afp);
463 ip->i_afp = NULL;
464 xfs_idestroy_fork(ip, XFS_DATA_FORK);
465 }
466 return error;
467}
468
469
470
471
472
473
474
475
476
477
478
479STATIC int
480xfs_iformat_local(
481 xfs_inode_t *ip,
482 xfs_dinode_t *dip,
483 int whichfork,
484 int size)
485{
486 xfs_ifork_t *ifp;
487 int real_size;
488
489
490
491
492
493
494 if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
495 xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
496 "corrupt inode %Lu "
497 "(bad size %d for local fork, size = %d).",
498 (unsigned long long) ip->i_ino, size,
499 XFS_DFORK_SIZE(dip, ip->i_mount, whichfork));
500 XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW,
501 ip->i_mount, dip);
502 return XFS_ERROR(EFSCORRUPTED);
503 }
504 ifp = XFS_IFORK_PTR(ip, whichfork);
505 real_size = 0;
506 if (size == 0)
507 ifp->if_u1.if_data = NULL;
508 else if (size <= sizeof(ifp->if_u2.if_inline_data))
509 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
510 else {
511 real_size = roundup(size, 4);
512 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
513 }
514 ifp->if_bytes = size;
515 ifp->if_real_bytes = real_size;
516 if (size)
517 memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size);
518 ifp->if_flags &= ~XFS_IFEXTENTS;
519 ifp->if_flags |= XFS_IFINLINE;
520 return 0;
521}
522
523
524
525
526
527
528
529
530
531
532STATIC int
533xfs_iformat_extents(
534 xfs_inode_t *ip,
535 xfs_dinode_t *dip,
536 int whichfork)
537{
538 xfs_bmbt_rec_t *dp;
539 xfs_ifork_t *ifp;
540 int nex;
541 int size;
542 int i;
543
544 ifp = XFS_IFORK_PTR(ip, whichfork);
545 nex = XFS_DFORK_NEXTENTS(dip, whichfork);
546 size = nex * (uint)sizeof(xfs_bmbt_rec_t);
547
548
549
550
551
552
553 if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
554 xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
555 "corrupt inode %Lu ((a)extents = %d).",
556 (unsigned long long) ip->i_ino, nex);
557 XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW,
558 ip->i_mount, dip);
559 return XFS_ERROR(EFSCORRUPTED);
560 }
561
562 ifp->if_real_bytes = 0;
563 if (nex == 0)
564 ifp->if_u1.if_extents = NULL;
565 else if (nex <= XFS_INLINE_EXTS)
566 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
567 else
568 xfs_iext_add(ifp, 0, nex);
569
570 ifp->if_bytes = size;
571 if (size) {
572 dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork);
573 xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip));
574 for (i = 0; i < nex; i++, dp++) {
575 xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
576 ep->l0 = get_unaligned_be64(&dp->l0);
577 ep->l1 = get_unaligned_be64(&dp->l1);
578 }
579 XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork);
580 if (whichfork != XFS_DATA_FORK ||
581 XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE)
582 if (unlikely(xfs_check_nostate_extents(
583 ifp, 0, nex))) {
584 XFS_ERROR_REPORT("xfs_iformat_extents(2)",
585 XFS_ERRLEVEL_LOW,
586 ip->i_mount);
587 return XFS_ERROR(EFSCORRUPTED);
588 }
589 }
590 ifp->if_flags |= XFS_IFEXTENTS;
591 return 0;
592}
593
594
595
596
597
598
599
600
601
602STATIC int
603xfs_iformat_btree(
604 xfs_inode_t *ip,
605 xfs_dinode_t *dip,
606 int whichfork)
607{
608 xfs_bmdr_block_t *dfp;
609 xfs_ifork_t *ifp;
610
611 int nrecs;
612 int size;
613
614 ifp = XFS_IFORK_PTR(ip, whichfork);
615 dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
616 size = XFS_BMAP_BROOT_SPACE(dfp);
617 nrecs = be16_to_cpu(dfp->bb_numrecs);
618
619
620
621
622
623
624
625
626 if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max
627 || XFS_BMDR_SPACE_CALC(nrecs) >
628 XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)
629 || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
630 xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
631 "corrupt inode %Lu (btree).",
632 (unsigned long long) ip->i_ino);
633 XFS_ERROR_REPORT("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
634 ip->i_mount);
635 return XFS_ERROR(EFSCORRUPTED);
636 }
637
638 ifp->if_broot_bytes = size;
639 ifp->if_broot = kmem_alloc(size, KM_SLEEP);
640 ASSERT(ifp->if_broot != NULL);
641
642
643
644
645 xfs_bmdr_to_bmbt(ip->i_mount, dfp,
646 XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),
647 ifp->if_broot, size);
648 ifp->if_flags &= ~XFS_IFEXTENTS;
649 ifp->if_flags |= XFS_IFBROOT;
650
651 return 0;
652}
653
654STATIC void
655xfs_dinode_from_disk(
656 xfs_icdinode_t *to,
657 xfs_dinode_t *from)
658{
659 to->di_magic = be16_to_cpu(from->di_magic);
660 to->di_mode = be16_to_cpu(from->di_mode);
661 to->di_version = from ->di_version;
662 to->di_format = from->di_format;
663 to->di_onlink = be16_to_cpu(from->di_onlink);
664 to->di_uid = be32_to_cpu(from->di_uid);
665 to->di_gid = be32_to_cpu(from->di_gid);
666 to->di_nlink = be32_to_cpu(from->di_nlink);
667 to->di_projid = be16_to_cpu(from->di_projid);
668 memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
669 to->di_flushiter = be16_to_cpu(from->di_flushiter);
670 to->di_atime.t_sec = be32_to_cpu(from->di_atime.t_sec);
671 to->di_atime.t_nsec = be32_to_cpu(from->di_atime.t_nsec);
672 to->di_mtime.t_sec = be32_to_cpu(from->di_mtime.t_sec);
673 to->di_mtime.t_nsec = be32_to_cpu(from->di_mtime.t_nsec);
674 to->di_ctime.t_sec = be32_to_cpu(from->di_ctime.t_sec);
675 to->di_ctime.t_nsec = be32_to_cpu(from->di_ctime.t_nsec);
676 to->di_size = be64_to_cpu(from->di_size);
677 to->di_nblocks = be64_to_cpu(from->di_nblocks);
678 to->di_extsize = be32_to_cpu(from->di_extsize);
679 to->di_nextents = be32_to_cpu(from->di_nextents);
680 to->di_anextents = be16_to_cpu(from->di_anextents);
681 to->di_forkoff = from->di_forkoff;
682 to->di_aformat = from->di_aformat;
683 to->di_dmevmask = be32_to_cpu(from->di_dmevmask);
684 to->di_dmstate = be16_to_cpu(from->di_dmstate);
685 to->di_flags = be16_to_cpu(from->di_flags);
686 to->di_gen = be32_to_cpu(from->di_gen);
687}
688
689void
690xfs_dinode_to_disk(
691 xfs_dinode_t *to,
692 xfs_icdinode_t *from)
693{
694 to->di_magic = cpu_to_be16(from->di_magic);
695 to->di_mode = cpu_to_be16(from->di_mode);
696 to->di_version = from ->di_version;
697 to->di_format = from->di_format;
698 to->di_onlink = cpu_to_be16(from->di_onlink);
699 to->di_uid = cpu_to_be32(from->di_uid);
700 to->di_gid = cpu_to_be32(from->di_gid);
701 to->di_nlink = cpu_to_be32(from->di_nlink);
702 to->di_projid = cpu_to_be16(from->di_projid);
703 memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
704 to->di_flushiter = cpu_to_be16(from->di_flushiter);
705 to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec);
706 to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec);
707 to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec);
708 to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec);
709 to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec);
710 to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec);
711 to->di_size = cpu_to_be64(from->di_size);
712 to->di_nblocks = cpu_to_be64(from->di_nblocks);
713 to->di_extsize = cpu_to_be32(from->di_extsize);
714 to->di_nextents = cpu_to_be32(from->di_nextents);
715 to->di_anextents = cpu_to_be16(from->di_anextents);
716 to->di_forkoff = from->di_forkoff;
717 to->di_aformat = from->di_aformat;
718 to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
719 to->di_dmstate = cpu_to_be16(from->di_dmstate);
720 to->di_flags = cpu_to_be16(from->di_flags);
721 to->di_gen = cpu_to_be32(from->di_gen);
722}
723
724STATIC uint
725_xfs_dic2xflags(
726 __uint16_t di_flags)
727{
728 uint flags = 0;
729
730 if (di_flags & XFS_DIFLAG_ANY) {
731 if (di_flags & XFS_DIFLAG_REALTIME)
732 flags |= XFS_XFLAG_REALTIME;
733 if (di_flags & XFS_DIFLAG_PREALLOC)
734 flags |= XFS_XFLAG_PREALLOC;
735 if (di_flags & XFS_DIFLAG_IMMUTABLE)
736 flags |= XFS_XFLAG_IMMUTABLE;
737 if (di_flags & XFS_DIFLAG_APPEND)
738 flags |= XFS_XFLAG_APPEND;
739 if (di_flags & XFS_DIFLAG_SYNC)
740 flags |= XFS_XFLAG_SYNC;
741 if (di_flags & XFS_DIFLAG_NOATIME)
742 flags |= XFS_XFLAG_NOATIME;
743 if (di_flags & XFS_DIFLAG_NODUMP)
744 flags |= XFS_XFLAG_NODUMP;
745 if (di_flags & XFS_DIFLAG_RTINHERIT)
746 flags |= XFS_XFLAG_RTINHERIT;
747 if (di_flags & XFS_DIFLAG_PROJINHERIT)
748 flags |= XFS_XFLAG_PROJINHERIT;
749 if (di_flags & XFS_DIFLAG_NOSYMLINKS)
750 flags |= XFS_XFLAG_NOSYMLINKS;
751 if (di_flags & XFS_DIFLAG_EXTSIZE)
752 flags |= XFS_XFLAG_EXTSIZE;
753 if (di_flags & XFS_DIFLAG_EXTSZINHERIT)
754 flags |= XFS_XFLAG_EXTSZINHERIT;
755 if (di_flags & XFS_DIFLAG_NODEFRAG)
756 flags |= XFS_XFLAG_NODEFRAG;
757 if (di_flags & XFS_DIFLAG_FILESTREAM)
758 flags |= XFS_XFLAG_FILESTREAM;
759 }
760
761 return flags;
762}
763
764uint
765xfs_ip2xflags(
766 xfs_inode_t *ip)
767{
768 xfs_icdinode_t *dic = &ip->i_d;
769
770 return _xfs_dic2xflags(dic->di_flags) |
771 (XFS_IFORK_Q(ip) ? XFS_XFLAG_HASATTR : 0);
772}
773
774uint
775xfs_dic2xflags(
776 xfs_dinode_t *dip)
777{
778 return _xfs_dic2xflags(be16_to_cpu(dip->di_flags)) |
779 (XFS_DFORK_Q(dip) ? XFS_XFLAG_HASATTR : 0);
780}
781
782
783
784
785int
786xfs_iread(
787 xfs_mount_t *mp,
788 xfs_trans_t *tp,
789 xfs_inode_t *ip,
790 xfs_daddr_t bno,
791 uint iget_flags)
792{
793 xfs_buf_t *bp;
794 xfs_dinode_t *dip;
795 int error;
796
797
798
799
800 ip->i_imap.im_blkno = bno;
801 error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags);
802 if (error)
803 return error;
804 ASSERT(bno == 0 || bno == ip->i_imap.im_blkno);
805
806
807
808
809 error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp,
810 XFS_BUF_LOCK, iget_flags);
811 if (error)
812 return error;
813 dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
814
815
816
817
818
819 if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC) {
820#ifdef DEBUG
821 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: "
822 "dip->di_magic (0x%x) != "
823 "XFS_DINODE_MAGIC (0x%x)",
824 be16_to_cpu(dip->di_magic),
825 XFS_DINODE_MAGIC);
826#endif
827 error = XFS_ERROR(EINVAL);
828 goto out_brelse;
829 }
830
831
832
833
834
835
836
837
838 if (dip->di_mode) {
839 xfs_dinode_from_disk(&ip->i_d, dip);
840 error = xfs_iformat(ip, dip);
841 if (error) {
842#ifdef DEBUG
843 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: "
844 "xfs_iformat() returned error %d",
845 error);
846#endif
847 goto out_brelse;
848 }
849 } else {
850 ip->i_d.di_magic = be16_to_cpu(dip->di_magic);
851 ip->i_d.di_version = dip->di_version;
852 ip->i_d.di_gen = be32_to_cpu(dip->di_gen);
853 ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter);
854
855
856
857
858
859
860
861 ip->i_d.di_mode = 0;
862
863
864
865
866 ip->i_df.if_ext_max =
867 XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
868 }
869
870
871
872
873
874
875
876
877
878
879
880
881 if (ip->i_d.di_version == 1) {
882 ip->i_d.di_nlink = ip->i_d.di_onlink;
883 ip->i_d.di_onlink = 0;
884 ip->i_d.di_projid = 0;
885 }
886
887 ip->i_delayed_blks = 0;
888 ip->i_size = ip->i_d.di_size;
889
890
891
892
893
894
895 XFS_BUF_SET_REF(bp, XFS_INO_REF);
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910 out_brelse:
911 xfs_trans_brelse(tp, bp);
912 return error;
913}
914
915
916
917
918
919int
920xfs_iread_extents(
921 xfs_trans_t *tp,
922 xfs_inode_t *ip,
923 int whichfork)
924{
925 int error;
926 xfs_ifork_t *ifp;
927 xfs_extnum_t nextents;
928 size_t size;
929
930 if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
931 XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW,
932 ip->i_mount);
933 return XFS_ERROR(EFSCORRUPTED);
934 }
935 nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
936 size = nextents * sizeof(xfs_bmbt_rec_t);
937 ifp = XFS_IFORK_PTR(ip, whichfork);
938
939
940
941
942 ifp->if_lastex = NULLEXTNUM;
943 ifp->if_bytes = ifp->if_real_bytes = 0;
944 ifp->if_flags |= XFS_IFEXTENTS;
945 xfs_iext_add(ifp, 0, nextents);
946 error = xfs_bmap_read_extents(tp, ip, whichfork);
947 if (error) {
948 xfs_iext_destroy(ifp);
949 ifp->if_flags &= ~XFS_IFEXTENTS;
950 return error;
951 }
952 xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip));
953 return 0;
954}
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987int
988xfs_ialloc(
989 xfs_trans_t *tp,
990 xfs_inode_t *pip,
991 mode_t mode,
992 xfs_nlink_t nlink,
993 xfs_dev_t rdev,
994 cred_t *cr,
995 xfs_prid_t prid,
996 int okalloc,
997 xfs_buf_t **ialloc_context,
998 boolean_t *call_again,
999 xfs_inode_t **ipp)
1000{
1001 xfs_ino_t ino;
1002 xfs_inode_t *ip;
1003 uint flags;
1004 int error;
1005 timespec_t tv;
1006 int filestreams = 0;
1007
1008
1009
1010
1011
1012 error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc,
1013 ialloc_context, call_again, &ino);
1014 if (error)
1015 return error;
1016 if (*call_again || ino == NULLFSINO) {
1017 *ipp = NULL;
1018 return 0;
1019 }
1020 ASSERT(*ialloc_context == NULL);
1021
1022
1023
1024
1025
1026
1027 error = xfs_trans_iget(tp->t_mountp, tp, ino,
1028 XFS_IGET_CREATE, XFS_ILOCK_EXCL, &ip);
1029 if (error)
1030 return error;
1031 ASSERT(ip != NULL);
1032
1033 ip->i_d.di_mode = (__uint16_t)mode;
1034 ip->i_d.di_onlink = 0;
1035 ip->i_d.di_nlink = nlink;
1036 ASSERT(ip->i_d.di_nlink == nlink);
1037 ip->i_d.di_uid = current_fsuid();
1038 ip->i_d.di_gid = current_fsgid();
1039 ip->i_d.di_projid = prid;
1040 memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
1041
1042
1043
1044
1045
1046
1047
1048 if (xfs_sb_version_hasnlink(&tp->t_mountp->m_sb) &&
1049 ip->i_d.di_version == 1) {
1050 ip->i_d.di_version = 2;
1051
1052
1053
1054
1055 }
1056
1057
1058
1059
1060 if ((prid != 0) && (ip->i_d.di_version == 1))
1061 xfs_bump_ino_vers2(tp, ip);
1062
1063 if (pip && XFS_INHERIT_GID(pip)) {
1064 ip->i_d.di_gid = pip->i_d.di_gid;
1065 if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR) {
1066 ip->i_d.di_mode |= S_ISGID;
1067 }
1068 }
1069
1070
1071
1072
1073
1074
1075 if ((irix_sgid_inherit) &&
1076 (ip->i_d.di_mode & S_ISGID) &&
1077 (!in_group_p((gid_t)ip->i_d.di_gid))) {
1078 ip->i_d.di_mode &= ~S_ISGID;
1079 }
1080
1081 ip->i_d.di_size = 0;
1082 ip->i_size = 0;
1083 ip->i_d.di_nextents = 0;
1084 ASSERT(ip->i_d.di_nblocks == 0);
1085
1086 nanotime(&tv);
1087 ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
1088 ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
1089 ip->i_d.di_atime = ip->i_d.di_mtime;
1090 ip->i_d.di_ctime = ip->i_d.di_mtime;
1091
1092
1093
1094
1095 ip->i_d.di_extsize = 0;
1096 ip->i_d.di_dmevmask = 0;
1097 ip->i_d.di_dmstate = 0;
1098 ip->i_d.di_flags = 0;
1099 flags = XFS_ILOG_CORE;
1100 switch (mode & S_IFMT) {
1101 case S_IFIFO:
1102 case S_IFCHR:
1103 case S_IFBLK:
1104 case S_IFSOCK:
1105 ip->i_d.di_format = XFS_DINODE_FMT_DEV;
1106 ip->i_df.if_u2.if_rdev = rdev;
1107 ip->i_df.if_flags = 0;
1108 flags |= XFS_ILOG_DEV;
1109 break;
1110 case S_IFREG:
1111
1112
1113
1114
1115 if (pip && xfs_inode_is_filestream(pip))
1116 filestreams = 1;
1117
1118 case S_IFDIR:
1119 if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
1120 uint di_flags = 0;
1121
1122 if ((mode & S_IFMT) == S_IFDIR) {
1123 if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT)
1124 di_flags |= XFS_DIFLAG_RTINHERIT;
1125 if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) {
1126 di_flags |= XFS_DIFLAG_EXTSZINHERIT;
1127 ip->i_d.di_extsize = pip->i_d.di_extsize;
1128 }
1129 } else if ((mode & S_IFMT) == S_IFREG) {
1130 if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT)
1131 di_flags |= XFS_DIFLAG_REALTIME;
1132 if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) {
1133 di_flags |= XFS_DIFLAG_EXTSIZE;
1134 ip->i_d.di_extsize = pip->i_d.di_extsize;
1135 }
1136 }
1137 if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) &&
1138 xfs_inherit_noatime)
1139 di_flags |= XFS_DIFLAG_NOATIME;
1140 if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) &&
1141 xfs_inherit_nodump)
1142 di_flags |= XFS_DIFLAG_NODUMP;
1143 if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) &&
1144 xfs_inherit_sync)
1145 di_flags |= XFS_DIFLAG_SYNC;
1146 if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) &&
1147 xfs_inherit_nosymlinks)
1148 di_flags |= XFS_DIFLAG_NOSYMLINKS;
1149 if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
1150 di_flags |= XFS_DIFLAG_PROJINHERIT;
1151 if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) &&
1152 xfs_inherit_nodefrag)
1153 di_flags |= XFS_DIFLAG_NODEFRAG;
1154 if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM)
1155 di_flags |= XFS_DIFLAG_FILESTREAM;
1156 ip->i_d.di_flags |= di_flags;
1157 }
1158
1159 case S_IFLNK:
1160 ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
1161 ip->i_df.if_flags = XFS_IFEXTENTS;
1162 ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0;
1163 ip->i_df.if_u1.if_extents = NULL;
1164 break;
1165 default:
1166 ASSERT(0);
1167 }
1168
1169
1170
1171 ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
1172 ip->i_d.di_anextents = 0;
1173
1174
1175
1176
1177 xfs_trans_log_inode(tp, ip, flags);
1178
1179
1180 xfs_setup_inode(ip);
1181
1182
1183 if (filestreams) {
1184 error = xfs_filestream_associate(pip, ip);
1185 if (error < 0)
1186 return -error;
1187 if (!error)
1188 xfs_iflags_set(ip, XFS_IFILESTREAM);
1189 }
1190
1191 *ipp = ip;
1192 return 0;
1193}
1194
1195
1196
1197
1198
1199
1200
1201#ifdef DEBUG
1202void
1203xfs_isize_check(
1204 xfs_mount_t *mp,
1205 xfs_inode_t *ip,
1206 xfs_fsize_t isize)
1207{
1208 xfs_fileoff_t map_first;
1209 int nimaps;
1210 xfs_bmbt_irec_t imaps[2];
1211
1212 if ((ip->i_d.di_mode & S_IFMT) != S_IFREG)
1213 return;
1214
1215 if (XFS_IS_REALTIME_INODE(ip))
1216 return;
1217
1218 if (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)
1219 return;
1220
1221 nimaps = 2;
1222 map_first = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize);
1223
1224
1225
1226
1227 if (xfs_bmapi(NULL, ip, map_first,
1228 (XFS_B_TO_FSB(mp,
1229 (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) -
1230 map_first),
1231 XFS_BMAPI_ENTIRE, NULL, 0, imaps, &nimaps,
1232 NULL, NULL))
1233 return;
1234 ASSERT(nimaps == 1);
1235 ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK);
1236}
1237#endif
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250STATIC xfs_fsize_t
1251xfs_file_last_byte(
1252 xfs_inode_t *ip)
1253{
1254 xfs_mount_t *mp;
1255 xfs_fsize_t last_byte;
1256 xfs_fileoff_t last_block;
1257 xfs_fileoff_t size_last_block;
1258 int error;
1259
1260 ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED));
1261
1262 mp = ip->i_mount;
1263
1264
1265
1266
1267
1268
1269 if (ip->i_df.if_flags & XFS_IFEXTENTS) {
1270 xfs_ilock(ip, XFS_ILOCK_SHARED);
1271 error = xfs_bmap_last_offset(NULL, ip, &last_block,
1272 XFS_DATA_FORK);
1273 xfs_iunlock(ip, XFS_ILOCK_SHARED);
1274 if (error) {
1275 last_block = 0;
1276 }
1277 } else {
1278 last_block = 0;
1279 }
1280 size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_size);
1281 last_block = XFS_FILEOFF_MAX(last_block, size_last_block);
1282
1283 last_byte = XFS_FSB_TO_B(mp, last_block);
1284 if (last_byte < 0) {
1285 return XFS_MAXIOFFSET(mp);
1286 }
1287 last_byte += (1 << mp->m_writeio_log);
1288 if (last_byte < 0) {
1289 return XFS_MAXIOFFSET(mp);
1290 }
1291 return last_byte;
1292}
1293
1294#if defined(XFS_RW_TRACE)
1295STATIC void
1296xfs_itrunc_trace(
1297 int tag,
1298 xfs_inode_t *ip,
1299 int flag,
1300 xfs_fsize_t new_size,
1301 xfs_off_t toss_start,
1302 xfs_off_t toss_finish)
1303{
1304 if (ip->i_rwtrace == NULL) {
1305 return;
1306 }
1307
1308 ktrace_enter(ip->i_rwtrace,
1309 (void*)((long)tag),
1310 (void*)ip,
1311 (void*)(unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff),
1312 (void*)(unsigned long)(ip->i_d.di_size & 0xffffffff),
1313 (void*)((long)flag),
1314 (void*)(unsigned long)((new_size >> 32) & 0xffffffff),
1315 (void*)(unsigned long)(new_size & 0xffffffff),
1316 (void*)(unsigned long)((toss_start >> 32) & 0xffffffff),
1317 (void*)(unsigned long)(toss_start & 0xffffffff),
1318 (void*)(unsigned long)((toss_finish >> 32) & 0xffffffff),
1319 (void*)(unsigned long)(toss_finish & 0xffffffff),
1320 (void*)(unsigned long)current_cpu(),
1321 (void*)(unsigned long)current_pid(),
1322 (void*)NULL,
1323 (void*)NULL,
1324 (void*)NULL);
1325}
1326#else
1327#define xfs_itrunc_trace(tag, ip, flag, new_size, toss_start, toss_finish)
1328#endif
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361int
1362xfs_itruncate_start(
1363 xfs_inode_t *ip,
1364 uint flags,
1365 xfs_fsize_t new_size)
1366{
1367 xfs_fsize_t last_byte;
1368 xfs_off_t toss_start;
1369 xfs_mount_t *mp;
1370 int error = 0;
1371
1372 ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
1373 ASSERT((new_size == 0) || (new_size <= ip->i_size));
1374 ASSERT((flags == XFS_ITRUNC_DEFINITE) ||
1375 (flags == XFS_ITRUNC_MAYBE));
1376
1377 mp = ip->i_mount;
1378
1379
1380 if (new_size == 0 || new_size < ip->i_size)
1381 xfs_ioend_wait(ip);
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401 toss_start = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size);
1402 toss_start = XFS_FSB_TO_B(mp, toss_start);
1403 if (toss_start < 0) {
1404
1405
1406
1407
1408
1409 return 0;
1410 }
1411 last_byte = xfs_file_last_byte(ip);
1412 xfs_itrunc_trace(XFS_ITRUNC_START, ip, flags, new_size, toss_start,
1413 last_byte);
1414 if (last_byte > toss_start) {
1415 if (flags & XFS_ITRUNC_DEFINITE) {
1416 xfs_tosspages(ip, toss_start,
1417 -1, FI_REMAPF_LOCKED);
1418 } else {
1419 error = xfs_flushinval_pages(ip, toss_start,
1420 -1, FI_REMAPF_LOCKED);
1421 }
1422 }
1423
1424#ifdef DEBUG
1425 if (new_size == 0) {
1426 ASSERT(VN_CACHED(VFS_I(ip)) == 0);
1427 }
1428#endif
1429 return error;
1430}
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478int
1479xfs_itruncate_finish(
1480 xfs_trans_t **tp,
1481 xfs_inode_t *ip,
1482 xfs_fsize_t new_size,
1483 int fork,
1484 int sync)
1485{
1486 xfs_fsblock_t first_block;
1487 xfs_fileoff_t first_unmap_block;
1488 xfs_fileoff_t last_block;
1489 xfs_filblks_t unmap_len=0;
1490 xfs_mount_t *mp;
1491 xfs_trans_t *ntp;
1492 int done;
1493 int committed;
1494 xfs_bmap_free_t free_list;
1495 int error;
1496
1497 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
1498 ASSERT((new_size == 0) || (new_size <= ip->i_size));
1499 ASSERT(*tp != NULL);
1500 ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
1501 ASSERT(ip->i_transp == *tp);
1502 ASSERT(ip->i_itemp != NULL);
1503 ASSERT(ip->i_itemp->ili_flags & XFS_ILI_HOLD);
1504
1505
1506 ntp = *tp;
1507 mp = (ntp)->t_mountp;
1508 ASSERT(! XFS_NOT_DQATTACHED(mp, ip));
1509
1510
1511
1512
1513 if (fork == XFS_ATTR_FORK) {
1514 new_size = 0LL;
1515 }
1516 first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size);
1517 xfs_itrunc_trace(XFS_ITRUNC_FINISH1, ip, 0, new_size, 0, 0);
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570 if (fork == XFS_DATA_FORK) {
1571 if (ip->i_d.di_nextents > 0) {
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581 if (ip->i_size != new_size) {
1582 ip->i_d.di_size = new_size;
1583 ip->i_size = new_size;
1584 xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
1585 }
1586 }
1587 } else if (sync) {
1588 ASSERT(!(mp->m_flags & XFS_MOUNT_WSYNC));
1589 if (ip->i_d.di_anextents > 0)
1590 xfs_trans_set_sync(ntp);
1591 }
1592 ASSERT(fork == XFS_DATA_FORK ||
1593 (fork == XFS_ATTR_FORK &&
1594 ((sync && !(mp->m_flags & XFS_MOUNT_WSYNC)) ||
1595 (sync == 0 && (mp->m_flags & XFS_MOUNT_WSYNC)))));
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606 last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
1607 ASSERT(first_unmap_block <= last_block);
1608 done = 0;
1609 if (last_block == first_unmap_block) {
1610 done = 1;
1611 } else {
1612 unmap_len = last_block - first_unmap_block + 1;
1613 }
1614 while (!done) {
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628 xfs_bmap_init(&free_list, &first_block);
1629 error = xfs_bunmapi(ntp, ip,
1630 first_unmap_block, unmap_len,
1631 xfs_bmapi_aflag(fork) |
1632 (sync ? 0 : XFS_BMAPI_ASYNC),
1633 XFS_ITRUNC_MAX_EXTENTS,
1634 &first_block, &free_list,
1635 NULL, &done);
1636 if (error) {
1637
1638
1639
1640
1641
1642
1643
1644 xfs_bmap_cancel(&free_list);
1645 return error;
1646 }
1647
1648
1649
1650
1651
1652 error = xfs_bmap_finish(tp, &free_list, &committed);
1653 ntp = *tp;
1654 if (committed) {
1655
1656 xfs_trans_ijoin(ntp, ip,
1657 XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
1658 xfs_trans_ihold(ntp, ip);
1659 }
1660
1661 if (error) {
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672 xfs_bmap_cancel(&free_list);
1673 return error;
1674 }
1675
1676 if (committed) {
1677
1678
1679
1680
1681 xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
1682 }
1683
1684 ntp = xfs_trans_dup(ntp);
1685 error = xfs_trans_commit(*tp, 0);
1686 *tp = ntp;
1687
1688
1689 xfs_trans_ijoin(ntp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
1690 xfs_trans_ihold(ntp, ip);
1691
1692 if (error)
1693 return error;
1694
1695
1696
1697
1698 xfs_log_ticket_put(ntp->t_ticket);
1699 error = xfs_trans_reserve(ntp, 0,
1700 XFS_ITRUNCATE_LOG_RES(mp), 0,
1701 XFS_TRANS_PERM_LOG_RES,
1702 XFS_ITRUNCATE_LOG_COUNT);
1703 if (error)
1704 return error;
1705 }
1706
1707
1708
1709
1710
1711 if (fork == XFS_DATA_FORK) {
1712 xfs_isize_check(mp, ip, new_size);
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722 if (ip->i_size != new_size) {
1723 ip->i_d.di_size = new_size;
1724 ip->i_size = new_size;
1725 }
1726 }
1727 xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
1728 ASSERT((new_size != 0) ||
1729 (fork == XFS_ATTR_FORK) ||
1730 (ip->i_delayed_blks == 0));
1731 ASSERT((new_size != 0) ||
1732 (fork == XFS_ATTR_FORK) ||
1733 (ip->i_d.di_nextents == 0));
1734 xfs_itrunc_trace(XFS_ITRUNC_FINISH2, ip, 0, new_size, 0, 0);
1735 return 0;
1736}
1737
1738
1739
1740
1741
1742
1743int
1744xfs_iunlink(
1745 xfs_trans_t *tp,
1746 xfs_inode_t *ip)
1747{
1748 xfs_mount_t *mp;
1749 xfs_agi_t *agi;
1750 xfs_dinode_t *dip;
1751 xfs_buf_t *agibp;
1752 xfs_buf_t *ibp;
1753 xfs_agino_t agino;
1754 short bucket_index;
1755 int offset;
1756 int error;
1757
1758 ASSERT(ip->i_d.di_nlink == 0);
1759 ASSERT(ip->i_d.di_mode != 0);
1760 ASSERT(ip->i_transp == tp);
1761
1762 mp = tp->t_mountp;
1763
1764
1765
1766
1767
1768 error = xfs_read_agi(mp, tp, XFS_INO_TO_AGNO(mp, ip->i_ino), &agibp);
1769 if (error)
1770 return error;
1771 agi = XFS_BUF_TO_AGI(agibp);
1772
1773
1774
1775
1776
1777 agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
1778 ASSERT(agino != 0);
1779 bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
1780 ASSERT(agi->agi_unlinked[bucket_index]);
1781 ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != agino);
1782
1783 if (be32_to_cpu(agi->agi_unlinked[bucket_index]) != NULLAGINO) {
1784
1785
1786
1787
1788
1789
1790 error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK);
1791 if (error)
1792 return error;
1793
1794 ASSERT(be32_to_cpu(dip->di_next_unlinked) == NULLAGINO);
1795
1796 dip->di_next_unlinked = agi->agi_unlinked[bucket_index];
1797 offset = ip->i_imap.im_boffset +
1798 offsetof(xfs_dinode_t, di_next_unlinked);
1799 xfs_trans_inode_buf(tp, ibp);
1800 xfs_trans_log_buf(tp, ibp, offset,
1801 (offset + sizeof(xfs_agino_t) - 1));
1802 xfs_inobp_check(mp, ibp);
1803 }
1804
1805
1806
1807
1808 ASSERT(agino != 0);
1809 agi->agi_unlinked[bucket_index] = cpu_to_be32(agino);
1810 offset = offsetof(xfs_agi_t, agi_unlinked) +
1811 (sizeof(xfs_agino_t) * bucket_index);
1812 xfs_trans_log_buf(tp, agibp, offset,
1813 (offset + sizeof(xfs_agino_t) - 1));
1814 return 0;
1815}
1816
1817
1818
1819
1820STATIC int
1821xfs_iunlink_remove(
1822 xfs_trans_t *tp,
1823 xfs_inode_t *ip)
1824{
1825 xfs_ino_t next_ino;
1826 xfs_mount_t *mp;
1827 xfs_agi_t *agi;
1828 xfs_dinode_t *dip;
1829 xfs_buf_t *agibp;
1830 xfs_buf_t *ibp;
1831 xfs_agnumber_t agno;
1832 xfs_agino_t agino;
1833 xfs_agino_t next_agino;
1834 xfs_buf_t *last_ibp;
1835 xfs_dinode_t *last_dip = NULL;
1836 short bucket_index;
1837 int offset, last_offset = 0;
1838 int error;
1839
1840 mp = tp->t_mountp;
1841 agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
1842
1843
1844
1845
1846
1847 error = xfs_read_agi(mp, tp, agno, &agibp);
1848 if (error)
1849 return error;
1850
1851 agi = XFS_BUF_TO_AGI(agibp);
1852
1853
1854
1855
1856
1857 agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
1858 ASSERT(agino != 0);
1859 bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
1860 ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != NULLAGINO);
1861 ASSERT(agi->agi_unlinked[bucket_index]);
1862
1863 if (be32_to_cpu(agi->agi_unlinked[bucket_index]) == agino) {
1864
1865
1866
1867
1868
1869
1870
1871
1872 error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK);
1873 if (error) {
1874 cmn_err(CE_WARN,
1875 "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.",
1876 error, mp->m_fsname);
1877 return error;
1878 }
1879 next_agino = be32_to_cpu(dip->di_next_unlinked);
1880 ASSERT(next_agino != 0);
1881 if (next_agino != NULLAGINO) {
1882 dip->di_next_unlinked = cpu_to_be32(NULLAGINO);
1883 offset = ip->i_imap.im_boffset +
1884 offsetof(xfs_dinode_t, di_next_unlinked);
1885 xfs_trans_inode_buf(tp, ibp);
1886 xfs_trans_log_buf(tp, ibp, offset,
1887 (offset + sizeof(xfs_agino_t) - 1));
1888 xfs_inobp_check(mp, ibp);
1889 } else {
1890 xfs_trans_brelse(tp, ibp);
1891 }
1892
1893
1894
1895 ASSERT(next_agino != 0);
1896 ASSERT(next_agino != agino);
1897 agi->agi_unlinked[bucket_index] = cpu_to_be32(next_agino);
1898 offset = offsetof(xfs_agi_t, agi_unlinked) +
1899 (sizeof(xfs_agino_t) * bucket_index);
1900 xfs_trans_log_buf(tp, agibp, offset,
1901 (offset + sizeof(xfs_agino_t) - 1));
1902 } else {
1903
1904
1905
1906 next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
1907 last_ibp = NULL;
1908 while (next_agino != agino) {
1909
1910
1911
1912
1913
1914 if (last_ibp != NULL) {
1915 xfs_trans_brelse(tp, last_ibp);
1916 }
1917 next_ino = XFS_AGINO_TO_INO(mp, agno, next_agino);
1918 error = xfs_inotobp(mp, tp, next_ino, &last_dip,
1919 &last_ibp, &last_offset, 0);
1920 if (error) {
1921 cmn_err(CE_WARN,
1922 "xfs_iunlink_remove: xfs_inotobp() returned an error %d on %s. Returning error.",
1923 error, mp->m_fsname);
1924 return error;
1925 }
1926 next_agino = be32_to_cpu(last_dip->di_next_unlinked);
1927 ASSERT(next_agino != NULLAGINO);
1928 ASSERT(next_agino != 0);
1929 }
1930
1931
1932
1933
1934 error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK);
1935 if (error) {
1936 cmn_err(CE_WARN,
1937 "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.",
1938 error, mp->m_fsname);
1939 return error;
1940 }
1941 next_agino = be32_to_cpu(dip->di_next_unlinked);
1942 ASSERT(next_agino != 0);
1943 ASSERT(next_agino != agino);
1944 if (next_agino != NULLAGINO) {
1945 dip->di_next_unlinked = cpu_to_be32(NULLAGINO);
1946 offset = ip->i_imap.im_boffset +
1947 offsetof(xfs_dinode_t, di_next_unlinked);
1948 xfs_trans_inode_buf(tp, ibp);
1949 xfs_trans_log_buf(tp, ibp, offset,
1950 (offset + sizeof(xfs_agino_t) - 1));
1951 xfs_inobp_check(mp, ibp);
1952 } else {
1953 xfs_trans_brelse(tp, ibp);
1954 }
1955
1956
1957
1958 last_dip->di_next_unlinked = cpu_to_be32(next_agino);
1959 ASSERT(next_agino != 0);
1960 offset = last_offset + offsetof(xfs_dinode_t, di_next_unlinked);
1961 xfs_trans_inode_buf(tp, last_ibp);
1962 xfs_trans_log_buf(tp, last_ibp, offset,
1963 (offset + sizeof(xfs_agino_t) - 1));
1964 xfs_inobp_check(mp, last_ibp);
1965 }
1966 return 0;
1967}
1968
1969STATIC void
1970xfs_ifree_cluster(
1971 xfs_inode_t *free_ip,
1972 xfs_trans_t *tp,
1973 xfs_ino_t inum)
1974{
1975 xfs_mount_t *mp = free_ip->i_mount;
1976 int blks_per_cluster;
1977 int nbufs;
1978 int ninodes;
1979 int i, j, found, pre_flushed;
1980 xfs_daddr_t blkno;
1981 xfs_buf_t *bp;
1982 xfs_inode_t *ip, **ip_found;
1983 xfs_inode_log_item_t *iip;
1984 xfs_log_item_t *lip;
1985 xfs_perag_t *pag = xfs_get_perag(mp, inum);
1986
1987 if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) {
1988 blks_per_cluster = 1;
1989 ninodes = mp->m_sb.sb_inopblock;
1990 nbufs = XFS_IALLOC_BLOCKS(mp);
1991 } else {
1992 blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) /
1993 mp->m_sb.sb_blocksize;
1994 ninodes = blks_per_cluster * mp->m_sb.sb_inopblock;
1995 nbufs = XFS_IALLOC_BLOCKS(mp) / blks_per_cluster;
1996 }
1997
1998 ip_found = kmem_alloc(ninodes * sizeof(xfs_inode_t *), KM_NOFS);
1999
2000 for (j = 0; j < nbufs; j++, inum += ninodes) {
2001 blkno = XFS_AGB_TO_DADDR(mp, XFS_INO_TO_AGNO(mp, inum),
2002 XFS_INO_TO_AGBNO(mp, inum));
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017 found = 0;
2018 for (i = 0; i < ninodes; i++) {
2019 read_lock(&pag->pag_ici_lock);
2020 ip = radix_tree_lookup(&pag->pag_ici_root,
2021 XFS_INO_TO_AGINO(mp, (inum + i)));
2022
2023
2024
2025
2026 if (!ip || xfs_iflags_test(ip, XFS_ISTALE)) {
2027 read_unlock(&pag->pag_ici_lock);
2028 continue;
2029 }
2030
2031 if (xfs_inode_clean(ip)) {
2032 read_unlock(&pag->pag_ici_lock);
2033 continue;
2034 }
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046 if (ip == free_ip) {
2047 if (xfs_iflock_nowait(ip)) {
2048 xfs_iflags_set(ip, XFS_ISTALE);
2049 if (xfs_inode_clean(ip)) {
2050 xfs_ifunlock(ip);
2051 } else {
2052 ip_found[found++] = ip;
2053 }
2054 }
2055 read_unlock(&pag->pag_ici_lock);
2056 continue;
2057 }
2058
2059 if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
2060 if (xfs_iflock_nowait(ip)) {
2061 xfs_iflags_set(ip, XFS_ISTALE);
2062
2063 if (xfs_inode_clean(ip)) {
2064 xfs_ifunlock(ip);
2065 xfs_iunlock(ip, XFS_ILOCK_EXCL);
2066 } else {
2067 ip_found[found++] = ip;
2068 }
2069 } else {
2070 xfs_iunlock(ip, XFS_ILOCK_EXCL);
2071 }
2072 }
2073 read_unlock(&pag->pag_ici_lock);
2074 }
2075
2076 bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno,
2077 mp->m_bsize * blks_per_cluster,
2078 XFS_BUF_LOCK);
2079
2080 pre_flushed = 0;
2081 lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
2082 while (lip) {
2083 if (lip->li_type == XFS_LI_INODE) {
2084 iip = (xfs_inode_log_item_t *)lip;
2085 ASSERT(iip->ili_logged == 1);
2086 lip->li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*)) xfs_istale_done;
2087 xfs_trans_ail_copy_lsn(mp->m_ail,
2088 &iip->ili_flush_lsn,
2089 &iip->ili_item.li_lsn);
2090 xfs_iflags_set(iip->ili_inode, XFS_ISTALE);
2091 pre_flushed++;
2092 }
2093 lip = lip->li_bio_list;
2094 }
2095
2096 for (i = 0; i < found; i++) {
2097 ip = ip_found[i];
2098 iip = ip->i_itemp;
2099
2100 if (!iip) {
2101 ip->i_update_core = 0;
2102 xfs_ifunlock(ip);
2103 xfs_iunlock(ip, XFS_ILOCK_EXCL);
2104 continue;
2105 }
2106
2107 iip->ili_last_fields = iip->ili_format.ilf_fields;
2108 iip->ili_format.ilf_fields = 0;
2109 iip->ili_logged = 1;
2110 xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
2111 &iip->ili_item.li_lsn);
2112
2113 xfs_buf_attach_iodone(bp,
2114 (void(*)(xfs_buf_t*,xfs_log_item_t*))
2115 xfs_istale_done, (xfs_log_item_t *)iip);
2116 if (ip != free_ip) {
2117 xfs_iunlock(ip, XFS_ILOCK_EXCL);
2118 }
2119 }
2120
2121 if (found || pre_flushed)
2122 xfs_trans_stale_inode_buf(tp, bp);
2123 xfs_trans_binval(tp, bp);
2124 }
2125
2126 kmem_free(ip_found);
2127 xfs_put_perag(mp, pag);
2128}
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140int
2141xfs_ifree(
2142 xfs_trans_t *tp,
2143 xfs_inode_t *ip,
2144 xfs_bmap_free_t *flist)
2145{
2146 int error;
2147 int delete;
2148 xfs_ino_t first_ino;
2149 xfs_dinode_t *dip;
2150 xfs_buf_t *ibp;
2151
2152 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
2153 ASSERT(ip->i_transp == tp);
2154 ASSERT(ip->i_d.di_nlink == 0);
2155 ASSERT(ip->i_d.di_nextents == 0);
2156 ASSERT(ip->i_d.di_anextents == 0);
2157 ASSERT((ip->i_d.di_size == 0 && ip->i_size == 0) ||
2158 ((ip->i_d.di_mode & S_IFMT) != S_IFREG));
2159 ASSERT(ip->i_d.di_nblocks == 0);
2160
2161
2162
2163
2164 error = xfs_iunlink_remove(tp, ip);
2165 if (error != 0) {
2166 return error;
2167 }
2168
2169 error = xfs_difree(tp, ip->i_ino, flist, &delete, &first_ino);
2170 if (error != 0) {
2171 return error;
2172 }
2173 ip->i_d.di_mode = 0;
2174 ip->i_d.di_flags = 0;
2175 ip->i_d.di_dmevmask = 0;
2176 ip->i_d.di_forkoff = 0;
2177 ip->i_df.if_ext_max =
2178 XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
2179 ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
2180 ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
2181
2182
2183
2184
2185 ip->i_d.di_gen++;
2186
2187 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
2188
2189 error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, XFS_BUF_LOCK);
2190 if (error)
2191 return error;
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205 dip->di_mode = 0;
2206
2207 if (delete) {
2208 xfs_ifree_cluster(ip, tp, first_ino);
2209 }
2210
2211 return 0;
2212}
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232void
2233xfs_iroot_realloc(
2234 xfs_inode_t *ip,
2235 int rec_diff,
2236 int whichfork)
2237{
2238 struct xfs_mount *mp = ip->i_mount;
2239 int cur_max;
2240 xfs_ifork_t *ifp;
2241 struct xfs_btree_block *new_broot;
2242 int new_max;
2243 size_t new_size;
2244 char *np;
2245 char *op;
2246
2247
2248
2249
2250 if (rec_diff == 0) {
2251 return;
2252 }
2253
2254 ifp = XFS_IFORK_PTR(ip, whichfork);
2255 if (rec_diff > 0) {
2256
2257
2258
2259
2260 if (ifp->if_broot_bytes == 0) {
2261 new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff);
2262 ifp->if_broot = kmem_alloc(new_size, KM_SLEEP);
2263 ifp->if_broot_bytes = (int)new_size;
2264 return;
2265 }
2266
2267
2268
2269
2270
2271
2272
2273 cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
2274 new_max = cur_max + rec_diff;
2275 new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max);
2276 ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
2277 (size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max),
2278 KM_SLEEP);
2279 op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
2280 ifp->if_broot_bytes);
2281 np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
2282 (int)new_size);
2283 ifp->if_broot_bytes = (int)new_size;
2284 ASSERT(ifp->if_broot_bytes <=
2285 XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ);
2286 memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t));
2287 return;
2288 }
2289
2290
2291
2292
2293
2294
2295 ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0));
2296 cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
2297 new_max = cur_max + rec_diff;
2298 ASSERT(new_max >= 0);
2299 if (new_max > 0)
2300 new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max);
2301 else
2302 new_size = 0;
2303 if (new_size > 0) {
2304 new_broot = kmem_alloc(new_size, KM_SLEEP);
2305
2306
2307
2308 memcpy(new_broot, ifp->if_broot, XFS_BTREE_LBLOCK_LEN);
2309 } else {
2310 new_broot = NULL;
2311 ifp->if_flags &= ~XFS_IFBROOT;
2312 }
2313
2314
2315
2316
2317 if (new_max > 0) {
2318
2319
2320
2321 op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1);
2322 np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1);
2323 memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
2324
2325
2326
2327
2328 op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
2329 ifp->if_broot_bytes);
2330 np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1,
2331 (int)new_size);
2332 memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t));
2333 }
2334 kmem_free(ifp->if_broot);
2335 ifp->if_broot = new_broot;
2336 ifp->if_broot_bytes = (int)new_size;
2337 ASSERT(ifp->if_broot_bytes <=
2338 XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ);
2339 return;
2340}
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358void
2359xfs_idata_realloc(
2360 xfs_inode_t *ip,
2361 int byte_diff,
2362 int whichfork)
2363{
2364 xfs_ifork_t *ifp;
2365 int new_size;
2366 int real_size;
2367
2368 if (byte_diff == 0) {
2369 return;
2370 }
2371
2372 ifp = XFS_IFORK_PTR(ip, whichfork);
2373 new_size = (int)ifp->if_bytes + byte_diff;
2374 ASSERT(new_size >= 0);
2375
2376 if (new_size == 0) {
2377 if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
2378 kmem_free(ifp->if_u1.if_data);
2379 }
2380 ifp->if_u1.if_data = NULL;
2381 real_size = 0;
2382 } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) {
2383
2384
2385
2386
2387 if (ifp->if_u1.if_data == NULL) {
2388 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
2389 } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
2390 ASSERT(ifp->if_real_bytes != 0);
2391 memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
2392 new_size);
2393 kmem_free(ifp->if_u1.if_data);
2394 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
2395 }
2396 real_size = 0;
2397 } else {
2398
2399
2400
2401
2402
2403
2404
2405 real_size = roundup(new_size, 4);
2406 if (ifp->if_u1.if_data == NULL) {
2407 ASSERT(ifp->if_real_bytes == 0);
2408 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
2409 } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
2410
2411
2412
2413
2414 if (ifp->if_real_bytes != real_size) {
2415 ifp->if_u1.if_data =
2416 kmem_realloc(ifp->if_u1.if_data,
2417 real_size,
2418 ifp->if_real_bytes,
2419 KM_SLEEP);
2420 }
2421 } else {
2422 ASSERT(ifp->if_real_bytes == 0);
2423 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
2424 memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
2425 ifp->if_bytes);
2426 }
2427 }
2428 ifp->if_real_bytes = real_size;
2429 ifp->if_bytes = new_size;
2430 ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
2431}
2432
2433void
2434xfs_idestroy_fork(
2435 xfs_inode_t *ip,
2436 int whichfork)
2437{
2438 xfs_ifork_t *ifp;
2439
2440 ifp = XFS_IFORK_PTR(ip, whichfork);
2441 if (ifp->if_broot != NULL) {
2442 kmem_free(ifp->if_broot);
2443 ifp->if_broot = NULL;
2444 }
2445
2446
2447
2448
2449
2450
2451
2452 if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
2453 if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) &&
2454 (ifp->if_u1.if_data != NULL)) {
2455 ASSERT(ifp->if_real_bytes != 0);
2456 kmem_free(ifp->if_u1.if_data);
2457 ifp->if_u1.if_data = NULL;
2458 ifp->if_real_bytes = 0;
2459 }
2460 } else if ((ifp->if_flags & XFS_IFEXTENTS) &&
2461 ((ifp->if_flags & XFS_IFEXTIREC) ||
2462 ((ifp->if_u1.if_extents != NULL) &&
2463 (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)))) {
2464 ASSERT(ifp->if_real_bytes != 0);
2465 xfs_iext_destroy(ifp);
2466 }
2467 ASSERT(ifp->if_u1.if_extents == NULL ||
2468 ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext);
2469 ASSERT(ifp->if_real_bytes == 0);
2470 if (whichfork == XFS_ATTR_FORK) {
2471 kmem_zone_free(xfs_ifork_zone, ip->i_afp);
2472 ip->i_afp = NULL;
2473 }
2474}
2475
2476
2477
2478
2479
2480void
2481xfs_ipin(
2482 xfs_inode_t *ip)
2483{
2484 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
2485
2486 atomic_inc(&ip->i_pincount);
2487}
2488
2489
2490
2491
2492
2493
2494void
2495xfs_iunpin(
2496 xfs_inode_t *ip)
2497{
2498 ASSERT(atomic_read(&ip->i_pincount) > 0);
2499
2500 if (atomic_dec_and_test(&ip->i_pincount))
2501 wake_up(&ip->i_ipin_wait);
2502}
2503
2504
2505
2506
2507
2508
2509
2510STATIC void
2511__xfs_iunpin_wait(
2512 xfs_inode_t *ip,
2513 int wait)
2514{
2515 xfs_inode_log_item_t *iip = ip->i_itemp;
2516
2517 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
2518 if (atomic_read(&ip->i_pincount) == 0)
2519 return;
2520
2521
2522 xfs_log_force(ip->i_mount, (iip && iip->ili_last_lsn) ?
2523 iip->ili_last_lsn : 0, XFS_LOG_FORCE);
2524 if (wait)
2525 wait_event(ip->i_ipin_wait, (atomic_read(&ip->i_pincount) == 0));
2526}
2527
2528static inline void
2529xfs_iunpin_wait(
2530 xfs_inode_t *ip)
2531{
2532 __xfs_iunpin_wait(ip, 1);
2533}
2534
2535static inline void
2536xfs_iunpin_nowait(
2537 xfs_inode_t *ip)
2538{
2539 __xfs_iunpin_wait(ip, 0);
2540}
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554int
2555xfs_iextents_copy(
2556 xfs_inode_t *ip,
2557 xfs_bmbt_rec_t *dp,
2558 int whichfork)
2559{
2560 int copied;
2561 int i;
2562 xfs_ifork_t *ifp;
2563 int nrecs;
2564 xfs_fsblock_t start_block;
2565
2566 ifp = XFS_IFORK_PTR(ip, whichfork);
2567 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
2568 ASSERT(ifp->if_bytes > 0);
2569
2570 nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
2571 XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork);
2572 ASSERT(nrecs > 0);
2573
2574
2575
2576
2577
2578
2579
2580 copied = 0;
2581 for (i = 0; i < nrecs; i++) {
2582 xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
2583 start_block = xfs_bmbt_get_startblock(ep);
2584 if (isnullstartblock(start_block)) {
2585
2586
2587
2588 continue;
2589 }
2590
2591
2592 put_unaligned(cpu_to_be64(ep->l0), &dp->l0);
2593 put_unaligned(cpu_to_be64(ep->l1), &dp->l1);
2594 dp++;
2595 copied++;
2596 }
2597 ASSERT(copied != 0);
2598 xfs_validate_extents(ifp, copied, XFS_EXTFMT_INODE(ip));
2599
2600 return (copied * (uint)sizeof(xfs_bmbt_rec_t));
2601}
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614STATIC void
2615xfs_iflush_fork(
2616 xfs_inode_t *ip,
2617 xfs_dinode_t *dip,
2618 xfs_inode_log_item_t *iip,
2619 int whichfork,
2620 xfs_buf_t *bp)
2621{
2622 char *cp;
2623 xfs_ifork_t *ifp;
2624 xfs_mount_t *mp;
2625#ifdef XFS_TRANS_DEBUG
2626 int first;
2627#endif
2628 static const short brootflag[2] =
2629 { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT };
2630 static const short dataflag[2] =
2631 { XFS_ILOG_DDATA, XFS_ILOG_ADATA };
2632 static const short extflag[2] =
2633 { XFS_ILOG_DEXT, XFS_ILOG_AEXT };
2634
2635 if (!iip)
2636 return;
2637 ifp = XFS_IFORK_PTR(ip, whichfork);
2638
2639
2640
2641
2642 if (!ifp) {
2643 ASSERT(whichfork == XFS_ATTR_FORK);
2644 return;
2645 }
2646 cp = XFS_DFORK_PTR(dip, whichfork);
2647 mp = ip->i_mount;
2648 switch (XFS_IFORK_FORMAT(ip, whichfork)) {
2649 case XFS_DINODE_FMT_LOCAL:
2650 if ((iip->ili_format.ilf_fields & dataflag[whichfork]) &&
2651 (ifp->if_bytes > 0)) {
2652 ASSERT(ifp->if_u1.if_data != NULL);
2653 ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
2654 memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes);
2655 }
2656 break;
2657
2658 case XFS_DINODE_FMT_EXTENTS:
2659 ASSERT((ifp->if_flags & XFS_IFEXTENTS) ||
2660 !(iip->ili_format.ilf_fields & extflag[whichfork]));
2661 ASSERT((xfs_iext_get_ext(ifp, 0) != NULL) ||
2662 (ifp->if_bytes == 0));
2663 ASSERT((xfs_iext_get_ext(ifp, 0) == NULL) ||
2664 (ifp->if_bytes > 0));
2665 if ((iip->ili_format.ilf_fields & extflag[whichfork]) &&
2666 (ifp->if_bytes > 0)) {
2667 ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
2668 (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp,
2669 whichfork);
2670 }
2671 break;
2672
2673 case XFS_DINODE_FMT_BTREE:
2674 if ((iip->ili_format.ilf_fields & brootflag[whichfork]) &&
2675 (ifp->if_broot_bytes > 0)) {
2676 ASSERT(ifp->if_broot != NULL);
2677 ASSERT(ifp->if_broot_bytes <=
2678 (XFS_IFORK_SIZE(ip, whichfork) +
2679 XFS_BROOT_SIZE_ADJ));
2680 xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,
2681 (xfs_bmdr_block_t *)cp,
2682 XFS_DFORK_SIZE(dip, mp, whichfork));
2683 }
2684 break;
2685
2686 case XFS_DINODE_FMT_DEV:
2687 if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) {
2688 ASSERT(whichfork == XFS_DATA_FORK);
2689 xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev);
2690 }
2691 break;
2692
2693 case XFS_DINODE_FMT_UUID:
2694 if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) {
2695 ASSERT(whichfork == XFS_DATA_FORK);
2696 memcpy(XFS_DFORK_DPTR(dip),
2697 &ip->i_df.if_u2.if_uuid,
2698 sizeof(uuid_t));
2699 }
2700 break;
2701
2702 default:
2703 ASSERT(0);
2704 break;
2705 }
2706}
2707
2708STATIC int
2709xfs_iflush_cluster(
2710 xfs_inode_t *ip,
2711 xfs_buf_t *bp)
2712{
2713 xfs_mount_t *mp = ip->i_mount;
2714 xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino);
2715 unsigned long first_index, mask;
2716 unsigned long inodes_per_cluster;
2717 int ilist_size;
2718 xfs_inode_t **ilist;
2719 xfs_inode_t *iq;
2720 int nr_found;
2721 int clcount = 0;
2722 int bufwasdelwri;
2723 int i;
2724
2725 ASSERT(pag->pagi_inodeok);
2726 ASSERT(pag->pag_ici_init);
2727
2728 inodes_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog;
2729 ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *);
2730 ilist = kmem_alloc(ilist_size, KM_MAYFAIL|KM_NOFS);
2731 if (!ilist)
2732 return 0;
2733
2734 mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1);
2735 first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask;
2736 read_lock(&pag->pag_ici_lock);
2737
2738 nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, (void**)ilist,
2739 first_index, inodes_per_cluster);
2740 if (nr_found == 0)
2741 goto out_free;
2742
2743 for (i = 0; i < nr_found; i++) {
2744 iq = ilist[i];
2745 if (iq == ip)
2746 continue;
2747
2748 if ((XFS_INO_TO_AGINO(mp, iq->i_ino) & mask) != first_index)
2749 break;
2750
2751
2752
2753
2754
2755 if (xfs_inode_clean(iq) && xfs_ipincount(iq) == 0)
2756 continue;
2757
2758
2759
2760
2761
2762
2763 if (!xfs_ilock_nowait(iq, XFS_ILOCK_SHARED))
2764 continue;
2765 if (!xfs_iflock_nowait(iq)) {
2766 xfs_iunlock(iq, XFS_ILOCK_SHARED);
2767 continue;
2768 }
2769 if (xfs_ipincount(iq)) {
2770 xfs_ifunlock(iq);
2771 xfs_iunlock(iq, XFS_ILOCK_SHARED);
2772 continue;
2773 }
2774
2775
2776
2777
2778
2779 if (!xfs_inode_clean(iq)) {
2780 int error;
2781 error = xfs_iflush_int(iq, bp);
2782 if (error) {
2783 xfs_iunlock(iq, XFS_ILOCK_SHARED);
2784 goto cluster_corrupt_out;
2785 }
2786 clcount++;
2787 } else {
2788 xfs_ifunlock(iq);
2789 }
2790 xfs_iunlock(iq, XFS_ILOCK_SHARED);
2791 }
2792
2793 if (clcount) {
2794 XFS_STATS_INC(xs_icluster_flushcnt);
2795 XFS_STATS_ADD(xs_icluster_flushinode, clcount);
2796 }
2797
2798out_free:
2799 read_unlock(&pag->pag_ici_lock);
2800 kmem_free(ilist);
2801 return 0;
2802
2803
2804cluster_corrupt_out:
2805
2806
2807
2808
2809 read_unlock(&pag->pag_ici_lock);
2810
2811
2812
2813
2814
2815 bufwasdelwri = XFS_BUF_ISDELAYWRITE(bp);
2816 if (bufwasdelwri)
2817 xfs_buf_relse(bp);
2818
2819 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
2820
2821 if (!bufwasdelwri) {
2822
2823
2824
2825
2826
2827 if (XFS_BUF_IODONE_FUNC(bp)) {
2828 XFS_BUF_CLR_BDSTRAT_FUNC(bp);
2829 XFS_BUF_UNDONE(bp);
2830 XFS_BUF_STALE(bp);
2831 XFS_BUF_ERROR(bp,EIO);
2832 xfs_biodone(bp);
2833 } else {
2834 XFS_BUF_STALE(bp);
2835 xfs_buf_relse(bp);
2836 }
2837 }
2838
2839
2840
2841
2842 xfs_iflush_abort(iq);
2843 kmem_free(ilist);
2844 return XFS_ERROR(EFSCORRUPTED);
2845}
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856int
2857xfs_iflush(
2858 xfs_inode_t *ip,
2859 uint flags)
2860{
2861 xfs_inode_log_item_t *iip;
2862 xfs_buf_t *bp;
2863 xfs_dinode_t *dip;
2864 xfs_mount_t *mp;
2865 int error;
2866 int noblock = (flags == XFS_IFLUSH_ASYNC_NOBLOCK);
2867 enum { INT_DELWRI = (1 << 0), INT_ASYNC = (1 << 1) };
2868
2869 XFS_STATS_INC(xs_iflush_count);
2870
2871 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
2872 ASSERT(!completion_done(&ip->i_flush));
2873 ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
2874 ip->i_d.di_nextents > ip->i_df.if_ext_max);
2875
2876 iip = ip->i_itemp;
2877 mp = ip->i_mount;
2878
2879
2880
2881
2882
2883 if (xfs_inode_clean(ip)) {
2884 xfs_ifunlock(ip);
2885 return 0;
2886 }
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899 if (noblock && xfs_ipincount(ip)) {
2900 xfs_iunpin_nowait(ip);
2901 xfs_ifunlock(ip);
2902 return EAGAIN;
2903 }
2904 xfs_iunpin_wait(ip);
2905
2906
2907
2908
2909
2910
2911 if (XFS_FORCED_SHUTDOWN(mp)) {
2912 ip->i_update_core = 0;
2913 if (iip)
2914 iip->ili_format.ilf_fields = 0;
2915 xfs_ifunlock(ip);
2916 return XFS_ERROR(EIO);
2917 }
2918
2919
2920
2921
2922
2923 if (iip != NULL && iip->ili_format.ilf_fields != 0) {
2924
2925
2926
2927
2928
2929
2930 switch (flags) {
2931 case XFS_IFLUSH_SYNC:
2932 case XFS_IFLUSH_DELWRI_ELSE_SYNC:
2933 flags = 0;
2934 break;
2935 case XFS_IFLUSH_ASYNC_NOBLOCK:
2936 case XFS_IFLUSH_ASYNC:
2937 case XFS_IFLUSH_DELWRI_ELSE_ASYNC:
2938 flags = INT_ASYNC;
2939 break;
2940 case XFS_IFLUSH_DELWRI:
2941 flags = INT_DELWRI;
2942 break;
2943 default:
2944 ASSERT(0);
2945 flags = 0;
2946 break;
2947 }
2948 } else {
2949 switch (flags) {
2950 case XFS_IFLUSH_DELWRI_ELSE_SYNC:
2951 case XFS_IFLUSH_DELWRI_ELSE_ASYNC:
2952 case XFS_IFLUSH_DELWRI:
2953 flags = INT_DELWRI;
2954 break;
2955 case XFS_IFLUSH_ASYNC_NOBLOCK:
2956 case XFS_IFLUSH_ASYNC:
2957 flags = INT_ASYNC;
2958 break;
2959 case XFS_IFLUSH_SYNC:
2960 flags = 0;
2961 break;
2962 default:
2963 ASSERT(0);
2964 flags = 0;
2965 break;
2966 }
2967 }
2968
2969
2970
2971
2972 error = xfs_itobp(mp, NULL, ip, &dip, &bp,
2973 noblock ? XFS_BUF_TRYLOCK : XFS_BUF_LOCK);
2974 if (error || !bp) {
2975 xfs_ifunlock(ip);
2976 return error;
2977 }
2978
2979
2980
2981
2982 error = xfs_iflush_int(ip, bp);
2983 if (error)
2984 goto corrupt_out;
2985
2986
2987
2988
2989
2990 if (XFS_BUF_ISPINNED(bp))
2991 xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
2992
2993
2994
2995
2996
2997 error = xfs_iflush_cluster(ip, bp);
2998 if (error)
2999 goto cluster_corrupt_out;
3000
3001 if (flags & INT_DELWRI) {
3002 xfs_bdwrite(mp, bp);
3003 } else if (flags & INT_ASYNC) {
3004 error = xfs_bawrite(mp, bp);
3005 } else {
3006 error = xfs_bwrite(mp, bp);
3007 }
3008 return error;
3009
3010corrupt_out:
3011 xfs_buf_relse(bp);
3012 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
3013cluster_corrupt_out:
3014
3015
3016
3017 xfs_iflush_abort(ip);
3018 return XFS_ERROR(EFSCORRUPTED);
3019}
3020
3021
3022STATIC int
3023xfs_iflush_int(
3024 xfs_inode_t *ip,
3025 xfs_buf_t *bp)
3026{
3027 xfs_inode_log_item_t *iip;
3028 xfs_dinode_t *dip;
3029 xfs_mount_t *mp;
3030#ifdef XFS_TRANS_DEBUG
3031 int first;
3032#endif
3033
3034 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
3035 ASSERT(!completion_done(&ip->i_flush));
3036 ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
3037 ip->i_d.di_nextents > ip->i_df.if_ext_max);
3038
3039 iip = ip->i_itemp;
3040 mp = ip->i_mount;
3041
3042
3043
3044
3045
3046
3047 if (xfs_inode_clean(ip)) {
3048 xfs_ifunlock(ip);
3049 return 0;
3050 }
3051
3052
3053 dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067 ip->i_update_core = 0;
3068 SYNCHRONIZE();
3069
3070
3071
3072
3073 xfs_synchronize_times(ip);
3074
3075 if (XFS_TEST_ERROR(be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC,
3076 mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {
3077 xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
3078 "xfs_iflush: Bad inode %Lu magic number 0x%x, ptr 0x%p",
3079 ip->i_ino, be16_to_cpu(dip->di_magic), dip);
3080 goto corrupt_out;
3081 }
3082 if (XFS_TEST_ERROR(ip->i_d.di_magic != XFS_DINODE_MAGIC,
3083 mp, XFS_ERRTAG_IFLUSH_2, XFS_RANDOM_IFLUSH_2)) {
3084 xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
3085 "xfs_iflush: Bad inode %Lu, ptr 0x%p, magic number 0x%x",
3086 ip->i_ino, ip, ip->i_d.di_magic);
3087 goto corrupt_out;
3088 }
3089 if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
3090 if (XFS_TEST_ERROR(
3091 (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
3092 (ip->i_d.di_format != XFS_DINODE_FMT_BTREE),
3093 mp, XFS_ERRTAG_IFLUSH_3, XFS_RANDOM_IFLUSH_3)) {
3094 xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
3095 "xfs_iflush: Bad regular inode %Lu, ptr 0x%p",
3096 ip->i_ino, ip);
3097 goto corrupt_out;
3098 }
3099 } else if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
3100 if (XFS_TEST_ERROR(
3101 (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
3102 (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
3103 (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL),
3104 mp, XFS_ERRTAG_IFLUSH_4, XFS_RANDOM_IFLUSH_4)) {
3105 xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
3106 "xfs_iflush: Bad directory inode %Lu, ptr 0x%p",
3107 ip->i_ino, ip);
3108 goto corrupt_out;
3109 }
3110 }
3111 if (XFS_TEST_ERROR(ip->i_d.di_nextents + ip->i_d.di_anextents >
3112 ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5,
3113 XFS_RANDOM_IFLUSH_5)) {
3114 xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
3115 "xfs_iflush: detected corrupt incore inode %Lu, total extents = %d, nblocks = %Ld, ptr 0x%p",
3116 ip->i_ino,
3117 ip->i_d.di_nextents + ip->i_d.di_anextents,
3118 ip->i_d.di_nblocks,
3119 ip);
3120 goto corrupt_out;
3121 }
3122 if (XFS_TEST_ERROR(ip->i_d.di_forkoff > mp->m_sb.sb_inodesize,
3123 mp, XFS_ERRTAG_IFLUSH_6, XFS_RANDOM_IFLUSH_6)) {
3124 xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
3125 "xfs_iflush: bad inode %Lu, forkoff 0x%x, ptr 0x%p",
3126 ip->i_ino, ip->i_d.di_forkoff, ip);
3127 goto corrupt_out;
3128 }
3129
3130
3131
3132
3133
3134 ip->i_d.di_flushiter++;
3135
3136
3137
3138
3139
3140
3141
3142 xfs_dinode_to_disk(dip, &ip->i_d);
3143
3144
3145 if (ip->i_d.di_flushiter == DI_MAX_FLUSH)
3146 ip->i_d.di_flushiter = 0;
3147
3148
3149
3150
3151
3152
3153
3154 ASSERT(ip->i_d.di_version == 1 || xfs_sb_version_hasnlink(&mp->m_sb));
3155 if (ip->i_d.di_version == 1) {
3156 if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
3157
3158
3159
3160 ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1);
3161 dip->di_onlink = cpu_to_be16(ip->i_d.di_nlink);
3162 } else {
3163
3164
3165
3166
3167
3168 ip->i_d.di_version = 2;
3169 dip->di_version = 2;
3170 ip->i_d.di_onlink = 0;
3171 dip->di_onlink = 0;
3172 memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
3173 memset(&(dip->di_pad[0]), 0,
3174 sizeof(dip->di_pad));
3175 ASSERT(ip->i_d.di_projid == 0);
3176 }
3177 }
3178
3179 xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp);
3180 if (XFS_IFORK_Q(ip))
3181 xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp);
3182 xfs_inobp_check(mp, bp);
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212 if (iip != NULL && iip->ili_format.ilf_fields != 0) {
3213 iip->ili_last_fields = iip->ili_format.ilf_fields;
3214 iip->ili_format.ilf_fields = 0;
3215 iip->ili_logged = 1;
3216
3217 xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
3218 &iip->ili_item.li_lsn);
3219
3220
3221
3222
3223
3224
3225
3226 xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t*,xfs_log_item_t*))
3227 xfs_iflush_done, (xfs_log_item_t *)iip);
3228
3229 ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
3230 ASSERT(XFS_BUF_IODONE_FUNC(bp) != NULL);
3231 } else {
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241 if (iip != NULL) {
3242 ASSERT(iip->ili_logged == 0);
3243 ASSERT(iip->ili_last_fields == 0);
3244 ASSERT((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0);
3245 }
3246 xfs_ifunlock(ip);
3247 }
3248
3249 return 0;
3250
3251corrupt_out:
3252 return XFS_ERROR(EFSCORRUPTED);
3253}
3254
3255
3256
3257#ifdef XFS_ILOCK_TRACE
3258void
3259xfs_ilock_trace(xfs_inode_t *ip, int lock, unsigned int lockflags, inst_t *ra)
3260{
3261 ktrace_enter(ip->i_lock_trace,
3262 (void *)ip,
3263 (void *)(unsigned long)lock,
3264 (void *)(unsigned long)lockflags,
3265 (void *)ra,
3266 (void *)(unsigned long)current_cpu(),
3267 (void *)(unsigned long)current_pid(),
3268 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
3269}
3270#endif
3271
3272
3273
3274
3275xfs_bmbt_rec_host_t *
3276xfs_iext_get_ext(
3277 xfs_ifork_t *ifp,
3278 xfs_extnum_t idx)
3279{
3280 ASSERT(idx >= 0);
3281 if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) {
3282 return ifp->if_u1.if_ext_irec->er_extbuf;
3283 } else if (ifp->if_flags & XFS_IFEXTIREC) {
3284 xfs_ext_irec_t *erp;
3285 int erp_idx = 0;
3286 xfs_extnum_t page_idx = idx;
3287
3288 erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0);
3289 return &erp->er_extbuf[page_idx];
3290 } else if (ifp->if_bytes) {
3291 return &ifp->if_u1.if_extents[idx];
3292 } else {
3293 return NULL;
3294 }
3295}
3296
3297
3298
3299
3300
3301void
3302xfs_iext_insert(
3303 xfs_ifork_t *ifp,
3304 xfs_extnum_t idx,
3305 xfs_extnum_t count,
3306 xfs_bmbt_irec_t *new)
3307{
3308 xfs_extnum_t i;
3309
3310 ASSERT(ifp->if_flags & XFS_IFEXTENTS);
3311 xfs_iext_add(ifp, idx, count);
3312 for (i = idx; i < idx + count; i++, new++)
3313 xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new);
3314}
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328void
3329xfs_iext_add(
3330 xfs_ifork_t *ifp,
3331 xfs_extnum_t idx,
3332 int ext_diff)
3333{
3334 int byte_diff;
3335 int new_size;
3336 xfs_extnum_t nextents;
3337
3338 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3339 ASSERT((idx >= 0) && (idx <= nextents));
3340 byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t);
3341 new_size = ifp->if_bytes + byte_diff;
3342
3343
3344
3345
3346
3347 if (nextents + ext_diff <= XFS_INLINE_EXTS) {
3348 if (idx < nextents) {
3349 memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff],
3350 &ifp->if_u2.if_inline_ext[idx],
3351 (nextents - idx) * sizeof(xfs_bmbt_rec_t));
3352 memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff);
3353 }
3354 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
3355 ifp->if_real_bytes = 0;
3356 ifp->if_lastex = nextents + ext_diff;
3357 }
3358
3359
3360
3361
3362
3363
3364 else if (nextents + ext_diff <= XFS_LINEAR_EXTS) {
3365 xfs_iext_realloc_direct(ifp, new_size);
3366 if (idx < nextents) {
3367 memmove(&ifp->if_u1.if_extents[idx + ext_diff],
3368 &ifp->if_u1.if_extents[idx],
3369 (nextents - idx) * sizeof(xfs_bmbt_rec_t));
3370 memset(&ifp->if_u1.if_extents[idx], 0, byte_diff);
3371 }
3372 }
3373
3374 else {
3375 xfs_ext_irec_t *erp;
3376 int erp_idx = 0;
3377 int page_idx = idx;
3378
3379 ASSERT(nextents + ext_diff > XFS_LINEAR_EXTS);
3380 if (ifp->if_flags & XFS_IFEXTIREC) {
3381 erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 1);
3382 } else {
3383 xfs_iext_irec_init(ifp);
3384 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3385 erp = ifp->if_u1.if_ext_irec;
3386 }
3387
3388 if (erp && erp->er_extcount + ext_diff <= XFS_LINEAR_EXTS) {
3389 if (page_idx < erp->er_extcount) {
3390 memmove(&erp->er_extbuf[page_idx + ext_diff],
3391 &erp->er_extbuf[page_idx],
3392 (erp->er_extcount - page_idx) *
3393 sizeof(xfs_bmbt_rec_t));
3394 memset(&erp->er_extbuf[page_idx], 0, byte_diff);
3395 }
3396 erp->er_extcount += ext_diff;
3397 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
3398 }
3399
3400 else if (erp) {
3401 xfs_iext_add_indirect_multi(ifp,
3402 erp_idx, page_idx, ext_diff);
3403 }
3404
3405
3406
3407
3408
3409
3410 else {
3411 int count = ext_diff;
3412
3413 while (count) {
3414 erp = xfs_iext_irec_new(ifp, erp_idx);
3415 erp->er_extcount = count;
3416 count -= MIN(count, (int)XFS_LINEAR_EXTS);
3417 if (count) {
3418 erp_idx++;
3419 }
3420 }
3421 }
3422 }
3423 ifp->if_bytes = new_size;
3424}
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442void
3443xfs_iext_add_indirect_multi(
3444 xfs_ifork_t *ifp,
3445 int erp_idx,
3446 xfs_extnum_t idx,
3447 int count)
3448{
3449 int byte_diff;
3450 xfs_ext_irec_t *erp;
3451 xfs_extnum_t ext_diff;
3452 xfs_extnum_t ext_cnt;
3453 xfs_extnum_t nex2;
3454 xfs_bmbt_rec_t *nex2_ep = NULL;
3455 int nlists;
3456
3457 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3458 erp = &ifp->if_u1.if_ext_irec[erp_idx];
3459 nex2 = erp->er_extcount - idx;
3460 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3461
3462
3463
3464
3465 if (nex2) {
3466 byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
3467 nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_NOFS);
3468 memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff);
3469 erp->er_extcount -= nex2;
3470 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2);
3471 memset(&erp->er_extbuf[idx], 0, byte_diff);
3472 }
3473
3474
3475
3476
3477
3478
3479
3480 ext_cnt = count;
3481 ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS - erp->er_extcount);
3482 if (ext_diff) {
3483 erp->er_extcount += ext_diff;
3484 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
3485 ext_cnt -= ext_diff;
3486 }
3487 while (ext_cnt) {
3488 erp_idx++;
3489 erp = xfs_iext_irec_new(ifp, erp_idx);
3490 ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS);
3491 erp->er_extcount = ext_diff;
3492 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
3493 ext_cnt -= ext_diff;
3494 }
3495
3496
3497 if (nex2) {
3498 xfs_extnum_t ext_avail;
3499 int i;
3500
3501 byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
3502 ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
3503 i = 0;
3504
3505
3506
3507
3508 if (nex2 <= ext_avail) {
3509 i = erp->er_extcount;
3510 }
3511
3512
3513
3514
3515 else if ((erp_idx < nlists - 1) &&
3516 (nex2 <= (ext_avail = XFS_LINEAR_EXTS -
3517 ifp->if_u1.if_ext_irec[erp_idx+1].er_extcount))) {
3518 erp_idx++;
3519 erp++;
3520
3521 memmove(&erp->er_extbuf[nex2], erp->er_extbuf,
3522 erp->er_extcount * sizeof(xfs_bmbt_rec_t));
3523 }
3524
3525
3526
3527
3528 else {
3529 erp_idx++;
3530 erp = xfs_iext_irec_new(ifp, erp_idx);
3531 }
3532 memmove(&erp->er_extbuf[i], nex2_ep, byte_diff);
3533 kmem_free(nex2_ep);
3534 erp->er_extcount += nex2;
3535 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2);
3536 }
3537}
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550void
3551xfs_iext_remove(
3552 xfs_ifork_t *ifp,
3553 xfs_extnum_t idx,
3554 int ext_diff)
3555{
3556 xfs_extnum_t nextents;
3557 int new_size;
3558
3559 ASSERT(ext_diff > 0);
3560 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3561 new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t);
3562
3563 if (new_size == 0) {
3564 xfs_iext_destroy(ifp);
3565 } else if (ifp->if_flags & XFS_IFEXTIREC) {
3566 xfs_iext_remove_indirect(ifp, idx, ext_diff);
3567 } else if (ifp->if_real_bytes) {
3568 xfs_iext_remove_direct(ifp, idx, ext_diff);
3569 } else {
3570 xfs_iext_remove_inline(ifp, idx, ext_diff);
3571 }
3572 ifp->if_bytes = new_size;
3573}
3574
3575
3576
3577
3578
3579void
3580xfs_iext_remove_inline(
3581 xfs_ifork_t *ifp,
3582 xfs_extnum_t idx,
3583 int ext_diff)
3584{
3585 int nextents;
3586
3587 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
3588 ASSERT(idx < XFS_INLINE_EXTS);
3589 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3590 ASSERT(((nextents - ext_diff) > 0) &&
3591 (nextents - ext_diff) < XFS_INLINE_EXTS);
3592
3593 if (idx + ext_diff < nextents) {
3594 memmove(&ifp->if_u2.if_inline_ext[idx],
3595 &ifp->if_u2.if_inline_ext[idx + ext_diff],
3596 (nextents - (idx + ext_diff)) *
3597 sizeof(xfs_bmbt_rec_t));
3598 memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff],
3599 0, ext_diff * sizeof(xfs_bmbt_rec_t));
3600 } else {
3601 memset(&ifp->if_u2.if_inline_ext[idx], 0,
3602 ext_diff * sizeof(xfs_bmbt_rec_t));
3603 }
3604}
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616void
3617xfs_iext_remove_direct(
3618 xfs_ifork_t *ifp,
3619 xfs_extnum_t idx,
3620 int ext_diff)
3621{
3622 xfs_extnum_t nextents;
3623 int new_size;
3624
3625 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
3626 new_size = ifp->if_bytes -
3627 (ext_diff * sizeof(xfs_bmbt_rec_t));
3628 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3629
3630 if (new_size == 0) {
3631 xfs_iext_destroy(ifp);
3632 return;
3633 }
3634
3635 if (idx + ext_diff < nextents) {
3636 memmove(&ifp->if_u1.if_extents[idx],
3637 &ifp->if_u1.if_extents[idx + ext_diff],
3638 (nextents - (idx + ext_diff)) *
3639 sizeof(xfs_bmbt_rec_t));
3640 }
3641 memset(&ifp->if_u1.if_extents[nextents - ext_diff],
3642 0, ext_diff * sizeof(xfs_bmbt_rec_t));
3643
3644
3645
3646
3647
3648
3649 xfs_iext_realloc_direct(ifp, new_size);
3650 ifp->if_bytes = new_size;
3651}
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668void
3669xfs_iext_remove_indirect(
3670 xfs_ifork_t *ifp,
3671 xfs_extnum_t idx,
3672 int count)
3673{
3674 xfs_ext_irec_t *erp;
3675 int erp_idx = 0;
3676 xfs_extnum_t ext_cnt;
3677 xfs_extnum_t ext_diff;
3678 xfs_extnum_t nex1;
3679 xfs_extnum_t nex2;
3680 int nlists;
3681 int page_idx = idx;
3682
3683 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3684 erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0);
3685 ASSERT(erp != NULL);
3686 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3687 nex1 = page_idx;
3688 ext_cnt = count;
3689 while (ext_cnt) {
3690 nex2 = MAX((erp->er_extcount - (nex1 + ext_cnt)), 0);
3691 ext_diff = MIN(ext_cnt, (erp->er_extcount - nex1));
3692
3693
3694
3695
3696 if (ext_diff == erp->er_extcount) {
3697 xfs_iext_irec_remove(ifp, erp_idx);
3698 ext_cnt -= ext_diff;
3699 nex1 = 0;
3700 if (ext_cnt) {
3701 ASSERT(erp_idx < ifp->if_real_bytes /
3702 XFS_IEXT_BUFSZ);
3703 erp = &ifp->if_u1.if_ext_irec[erp_idx];
3704 nex1 = 0;
3705 continue;
3706 } else {
3707 break;
3708 }
3709 }
3710
3711 if (nex2) {
3712 memmove(&erp->er_extbuf[nex1],
3713 &erp->er_extbuf[nex1 + ext_diff],
3714 nex2 * sizeof(xfs_bmbt_rec_t));
3715 }
3716
3717 memset(&erp->er_extbuf[nex1 + nex2], 0, (XFS_IEXT_BUFSZ -
3718 ((nex1 + nex2) * sizeof(xfs_bmbt_rec_t))));
3719
3720 erp->er_extcount -= ext_diff;
3721 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -ext_diff);
3722 ext_cnt -= ext_diff;
3723 nex1 = 0;
3724 erp_idx++;
3725 erp++;
3726 }
3727 ifp->if_bytes -= count * sizeof(xfs_bmbt_rec_t);
3728 xfs_iext_irec_compact(ifp);
3729}
3730
3731
3732
3733
3734void
3735xfs_iext_realloc_direct(
3736 xfs_ifork_t *ifp,
3737 int new_size)
3738{
3739 int rnew_size;
3740
3741 rnew_size = new_size;
3742
3743 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC) ||
3744 ((new_size >= 0) && (new_size <= XFS_IEXT_BUFSZ) &&
3745 (new_size != ifp->if_real_bytes)));
3746
3747
3748 if (new_size == 0) {
3749 xfs_iext_destroy(ifp);
3750 }
3751
3752 else if (ifp->if_real_bytes) {
3753
3754 if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) {
3755 xfs_iext_direct_to_inline(ifp, new_size /
3756 (uint)sizeof(xfs_bmbt_rec_t));
3757 ifp->if_bytes = new_size;
3758 return;
3759 }
3760 if (!is_power_of_2(new_size)){
3761 rnew_size = roundup_pow_of_two(new_size);
3762 }
3763 if (rnew_size != ifp->if_real_bytes) {
3764 ifp->if_u1.if_extents =
3765 kmem_realloc(ifp->if_u1.if_extents,
3766 rnew_size,
3767 ifp->if_real_bytes, KM_NOFS);
3768 }
3769 if (rnew_size > ifp->if_real_bytes) {
3770 memset(&ifp->if_u1.if_extents[ifp->if_bytes /
3771 (uint)sizeof(xfs_bmbt_rec_t)], 0,
3772 rnew_size - ifp->if_real_bytes);
3773 }
3774 }
3775
3776
3777
3778
3779
3780 else {
3781 new_size += ifp->if_bytes;
3782 if (!is_power_of_2(new_size)) {
3783 rnew_size = roundup_pow_of_two(new_size);
3784 }
3785 xfs_iext_inline_to_direct(ifp, rnew_size);
3786 }
3787 ifp->if_real_bytes = rnew_size;
3788 ifp->if_bytes = new_size;
3789}
3790
3791
3792
3793
3794void
3795xfs_iext_direct_to_inline(
3796 xfs_ifork_t *ifp,
3797 xfs_extnum_t nextents)
3798{
3799 ASSERT(ifp->if_flags & XFS_IFEXTENTS);
3800 ASSERT(nextents <= XFS_INLINE_EXTS);
3801
3802
3803
3804
3805
3806 memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
3807 nextents * sizeof(xfs_bmbt_rec_t));
3808 kmem_free(ifp->if_u1.if_extents);
3809 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
3810 ifp->if_real_bytes = 0;
3811}
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821void
3822xfs_iext_inline_to_direct(
3823 xfs_ifork_t *ifp,
3824 int new_size)
3825{
3826 ifp->if_u1.if_extents = kmem_alloc(new_size, KM_NOFS);
3827 memset(ifp->if_u1.if_extents, 0, new_size);
3828 if (ifp->if_bytes) {
3829 memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext,
3830 ifp->if_bytes);
3831 memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
3832 sizeof(xfs_bmbt_rec_t));
3833 }
3834 ifp->if_real_bytes = new_size;
3835}
3836
3837
3838
3839
3840STATIC void
3841xfs_iext_realloc_indirect(
3842 xfs_ifork_t *ifp,
3843 int new_size)
3844{
3845 int nlists;
3846 int size;
3847
3848 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3849 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3850 size = nlists * sizeof(xfs_ext_irec_t);
3851 ASSERT(ifp->if_real_bytes);
3852 ASSERT((new_size >= 0) && (new_size != size));
3853 if (new_size == 0) {
3854 xfs_iext_destroy(ifp);
3855 } else {
3856 ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *)
3857 kmem_realloc(ifp->if_u1.if_ext_irec,
3858 new_size, size, KM_NOFS);
3859 }
3860}
3861
3862
3863
3864
3865STATIC void
3866xfs_iext_indirect_to_direct(
3867 xfs_ifork_t *ifp)
3868{
3869 xfs_bmbt_rec_host_t *ep;
3870 xfs_extnum_t nextents;
3871 int size;
3872
3873 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3874 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3875 ASSERT(nextents <= XFS_LINEAR_EXTS);
3876 size = nextents * sizeof(xfs_bmbt_rec_t);
3877
3878 xfs_iext_irec_compact_pages(ifp);
3879 ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ);
3880
3881 ep = ifp->if_u1.if_ext_irec->er_extbuf;
3882 kmem_free(ifp->if_u1.if_ext_irec);
3883 ifp->if_flags &= ~XFS_IFEXTIREC;
3884 ifp->if_u1.if_extents = ep;
3885 ifp->if_bytes = size;
3886 if (nextents < XFS_LINEAR_EXTS) {
3887 xfs_iext_realloc_direct(ifp, size);
3888 }
3889}
3890
3891
3892
3893
3894void
3895xfs_iext_destroy(
3896 xfs_ifork_t *ifp)
3897{
3898 if (ifp->if_flags & XFS_IFEXTIREC) {
3899 int erp_idx;
3900 int nlists;
3901
3902 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3903 for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) {
3904 xfs_iext_irec_remove(ifp, erp_idx);
3905 }
3906 ifp->if_flags &= ~XFS_IFEXTIREC;
3907 } else if (ifp->if_real_bytes) {
3908 kmem_free(ifp->if_u1.if_extents);
3909 } else if (ifp->if_bytes) {
3910 memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
3911 sizeof(xfs_bmbt_rec_t));
3912 }
3913 ifp->if_u1.if_extents = NULL;
3914 ifp->if_real_bytes = 0;
3915 ifp->if_bytes = 0;
3916}
3917
3918
3919
3920
3921xfs_bmbt_rec_host_t *
3922xfs_iext_bno_to_ext(
3923 xfs_ifork_t *ifp,
3924 xfs_fileoff_t bno,
3925 xfs_extnum_t *idxp)
3926{
3927 xfs_bmbt_rec_host_t *base;
3928 xfs_filblks_t blockcount = 0;
3929 xfs_bmbt_rec_host_t *ep = NULL;
3930 xfs_ext_irec_t *erp = NULL;
3931 int high;
3932 xfs_extnum_t idx = 0;
3933 int low;
3934 xfs_extnum_t nextents;
3935 xfs_fileoff_t startoff = 0;
3936
3937 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3938 if (nextents == 0) {
3939 *idxp = 0;
3940 return NULL;
3941 }
3942 low = 0;
3943 if (ifp->if_flags & XFS_IFEXTIREC) {
3944
3945 int erp_idx = 0;
3946 erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx);
3947 base = erp->er_extbuf;
3948 high = erp->er_extcount - 1;
3949 } else {
3950 base = ifp->if_u1.if_extents;
3951 high = nextents - 1;
3952 }
3953
3954 while (low <= high) {
3955 idx = (low + high) >> 1;
3956 ep = base + idx;
3957 startoff = xfs_bmbt_get_startoff(ep);
3958 blockcount = xfs_bmbt_get_blockcount(ep);
3959 if (bno < startoff) {
3960 high = idx - 1;
3961 } else if (bno >= startoff + blockcount) {
3962 low = idx + 1;
3963 } else {
3964
3965 if (ifp->if_flags & XFS_IFEXTIREC) {
3966 idx += erp->er_extoff;
3967 }
3968 *idxp = idx;
3969 return ep;
3970 }
3971 }
3972
3973 if (ifp->if_flags & XFS_IFEXTIREC) {
3974 idx += erp->er_extoff;
3975 }
3976 if (bno >= startoff + blockcount) {
3977 if (++idx == nextents) {
3978 ep = NULL;
3979 } else {
3980 ep = xfs_iext_get_ext(ifp, idx);
3981 }
3982 }
3983 *idxp = idx;
3984 return ep;
3985}
3986
3987
3988
3989
3990
3991
3992xfs_ext_irec_t *
3993xfs_iext_bno_to_irec(
3994 xfs_ifork_t *ifp,
3995 xfs_fileoff_t bno,
3996 int *erp_idxp)
3997{
3998 xfs_ext_irec_t *erp = NULL;
3999 xfs_ext_irec_t *erp_next;
4000 int erp_idx;
4001 int nlists;
4002 int high;
4003 int low;
4004
4005 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4006 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4007 erp_idx = 0;
4008 low = 0;
4009 high = nlists - 1;
4010 while (low <= high) {
4011 erp_idx = (low + high) >> 1;
4012 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4013 erp_next = erp_idx < nlists - 1 ? erp + 1 : NULL;
4014 if (bno < xfs_bmbt_get_startoff(erp->er_extbuf)) {
4015 high = erp_idx - 1;
4016 } else if (erp_next && bno >=
4017 xfs_bmbt_get_startoff(erp_next->er_extbuf)) {
4018 low = erp_idx + 1;
4019 } else {
4020 break;
4021 }
4022 }
4023 *erp_idxp = erp_idx;
4024 return erp;
4025}
4026
4027
4028
4029
4030
4031
4032
4033xfs_ext_irec_t *
4034xfs_iext_idx_to_irec(
4035 xfs_ifork_t *ifp,
4036 xfs_extnum_t *idxp,
4037 int *erp_idxp,
4038 int realloc)
4039{
4040 xfs_ext_irec_t *prev;
4041 xfs_ext_irec_t *erp = NULL;
4042 int erp_idx;
4043 int nlists;
4044 int high;
4045 int low;
4046 xfs_extnum_t page_idx = *idxp;
4047
4048 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4049 ASSERT(page_idx >= 0 && page_idx <=
4050 ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
4051 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4052 erp_idx = 0;
4053 low = 0;
4054 high = nlists - 1;
4055
4056
4057 while (low <= high) {
4058 erp_idx = (low + high) >> 1;
4059 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4060 prev = erp_idx > 0 ? erp - 1 : NULL;
4061 if (page_idx < erp->er_extoff || (page_idx == erp->er_extoff &&
4062 realloc && prev && prev->er_extcount < XFS_LINEAR_EXTS)) {
4063 high = erp_idx - 1;
4064 } else if (page_idx > erp->er_extoff + erp->er_extcount ||
4065 (page_idx == erp->er_extoff + erp->er_extcount &&
4066 !realloc)) {
4067 low = erp_idx + 1;
4068 } else if (page_idx == erp->er_extoff + erp->er_extcount &&
4069 erp->er_extcount == XFS_LINEAR_EXTS) {
4070 ASSERT(realloc);
4071 page_idx = 0;
4072 erp_idx++;
4073 erp = erp_idx < nlists ? erp + 1 : NULL;
4074 break;
4075 } else {
4076 page_idx -= erp->er_extoff;
4077 break;
4078 }
4079 }
4080 *idxp = page_idx;
4081 *erp_idxp = erp_idx;
4082 return(erp);
4083}
4084
4085
4086
4087
4088
4089void
4090xfs_iext_irec_init(
4091 xfs_ifork_t *ifp)
4092{
4093 xfs_ext_irec_t *erp;
4094 xfs_extnum_t nextents;
4095
4096 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
4097 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
4098 ASSERT(nextents <= XFS_LINEAR_EXTS);
4099
4100 erp = kmem_alloc(sizeof(xfs_ext_irec_t), KM_NOFS);
4101
4102 if (nextents == 0) {
4103 ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS);
4104 } else if (!ifp->if_real_bytes) {
4105 xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ);
4106 } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) {
4107 xfs_iext_realloc_direct(ifp, XFS_IEXT_BUFSZ);
4108 }
4109 erp->er_extbuf = ifp->if_u1.if_extents;
4110 erp->er_extcount = nextents;
4111 erp->er_extoff = 0;
4112
4113 ifp->if_flags |= XFS_IFEXTIREC;
4114 ifp->if_real_bytes = XFS_IEXT_BUFSZ;
4115 ifp->if_bytes = nextents * sizeof(xfs_bmbt_rec_t);
4116 ifp->if_u1.if_ext_irec = erp;
4117
4118 return;
4119}
4120
4121
4122
4123
4124xfs_ext_irec_t *
4125xfs_iext_irec_new(
4126 xfs_ifork_t *ifp,
4127 int erp_idx)
4128{
4129 xfs_ext_irec_t *erp;
4130 int i;
4131 int nlists;
4132
4133 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4134 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4135
4136
4137 xfs_iext_realloc_indirect(ifp, ++nlists *
4138 sizeof(xfs_ext_irec_t));
4139
4140
4141
4142
4143 erp = ifp->if_u1.if_ext_irec;
4144 for (i = nlists - 1; i > erp_idx; i--) {
4145 memmove(&erp[i], &erp[i-1], sizeof(xfs_ext_irec_t));
4146 }
4147 ASSERT(i == erp_idx);
4148
4149
4150 erp = ifp->if_u1.if_ext_irec;
4151 erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS);
4152 ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
4153 memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ);
4154 erp[erp_idx].er_extcount = 0;
4155 erp[erp_idx].er_extoff = erp_idx > 0 ?
4156 erp[erp_idx-1].er_extoff + erp[erp_idx-1].er_extcount : 0;
4157 return (&erp[erp_idx]);
4158}
4159
4160
4161
4162
4163void
4164xfs_iext_irec_remove(
4165 xfs_ifork_t *ifp,
4166 int erp_idx)
4167{
4168 xfs_ext_irec_t *erp;
4169 int i;
4170 int nlists;
4171
4172 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4173 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4174 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4175 if (erp->er_extbuf) {
4176 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1,
4177 -erp->er_extcount);
4178 kmem_free(erp->er_extbuf);
4179 }
4180
4181 erp = ifp->if_u1.if_ext_irec;
4182 for (i = erp_idx; i < nlists - 1; i++) {
4183 memmove(&erp[i], &erp[i+1], sizeof(xfs_ext_irec_t));
4184 }
4185
4186
4187
4188
4189
4190
4191
4192 if (--nlists) {
4193 xfs_iext_realloc_indirect(ifp,
4194 nlists * sizeof(xfs_ext_irec_t));
4195 } else {
4196 kmem_free(ifp->if_u1.if_ext_irec);
4197 }
4198 ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
4199}
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212void
4213xfs_iext_irec_compact(
4214 xfs_ifork_t *ifp)
4215{
4216 xfs_extnum_t nextents;
4217 int nlists;
4218
4219 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4220 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4221 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
4222
4223 if (nextents == 0) {
4224 xfs_iext_destroy(ifp);
4225 } else if (nextents <= XFS_INLINE_EXTS) {
4226 xfs_iext_indirect_to_direct(ifp);
4227 xfs_iext_direct_to_inline(ifp, nextents);
4228 } else if (nextents <= XFS_LINEAR_EXTS) {
4229 xfs_iext_indirect_to_direct(ifp);
4230 } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) {
4231 xfs_iext_irec_compact_pages(ifp);
4232 }
4233}
4234
4235
4236
4237
4238void
4239xfs_iext_irec_compact_pages(
4240 xfs_ifork_t *ifp)
4241{
4242 xfs_ext_irec_t *erp, *erp_next;
4243 int erp_idx = 0;
4244 int nlists;
4245
4246 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4247 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4248 while (erp_idx < nlists - 1) {
4249 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4250 erp_next = erp + 1;
4251 if (erp_next->er_extcount <=
4252 (XFS_LINEAR_EXTS - erp->er_extcount)) {
4253 memcpy(&erp->er_extbuf[erp->er_extcount],
4254 erp_next->er_extbuf, erp_next->er_extcount *
4255 sizeof(xfs_bmbt_rec_t));
4256 erp->er_extcount += erp_next->er_extcount;
4257
4258
4259
4260
4261
4262 kmem_free(erp_next->er_extbuf);
4263 erp_next->er_extbuf = NULL;
4264 xfs_iext_irec_remove(ifp, erp_idx + 1);
4265 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4266 } else {
4267 erp_idx++;
4268 }
4269 }
4270}
4271
4272
4273
4274
4275
4276
4277
4278
4279void
4280xfs_iext_irec_update_extoffs(
4281 xfs_ifork_t *ifp,
4282 int erp_idx,
4283 int ext_diff)
4284{
4285 int i;
4286 int nlists;
4287
4288 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4289 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4290 for (i = erp_idx; i < nlists; i++) {
4291 ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff;
4292 }
4293}
4294