hc
2024-09-20 cf4ce59b3b70238352c7f1729f0f7223214828ad
kernel/fs/xfs/libxfs/xfs_dir2_sf.c
....@@ -5,16 +5,13 @@
55 */
66 #include "xfs.h"
77 #include "xfs_fs.h"
8
+#include "xfs_shared.h"
89 #include "xfs_format.h"
910 #include "xfs_log_format.h"
1011 #include "xfs_trans_resv.h"
1112 #include "xfs_mount.h"
12
-#include "xfs_da_format.h"
13
-#include "xfs_da_btree.h"
1413 #include "xfs_inode.h"
1514 #include "xfs_trans.h"
16
-#include "xfs_inode_item.h"
17
-#include "xfs_error.h"
1815 #include "xfs_dir2.h"
1916 #include "xfs_dir2_priv.h"
2017 #include "xfs_trace.h"
....@@ -39,6 +36,126 @@
3936
4037 static void xfs_dir2_sf_toino4(xfs_da_args_t *args);
4138 static void xfs_dir2_sf_toino8(xfs_da_args_t *args);
39
+
40
+int
41
+xfs_dir2_sf_entsize(
42
+ struct xfs_mount *mp,
43
+ struct xfs_dir2_sf_hdr *hdr,
44
+ int len)
45
+{
46
+ int count = len;
47
+
48
+ count += sizeof(struct xfs_dir2_sf_entry); /* namelen + offset */
49
+ count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE; /* ino # */
50
+
51
+ if (xfs_sb_version_hasftype(&mp->m_sb))
52
+ count += sizeof(uint8_t);
53
+ return count;
54
+}
55
+
56
+struct xfs_dir2_sf_entry *
57
+xfs_dir2_sf_nextentry(
58
+ struct xfs_mount *mp,
59
+ struct xfs_dir2_sf_hdr *hdr,
60
+ struct xfs_dir2_sf_entry *sfep)
61
+{
62
+ return (void *)sfep + xfs_dir2_sf_entsize(mp, hdr, sfep->namelen);
63
+}
64
+
65
+/*
66
+ * In short-form directory entries the inode numbers are stored at variable
67
+ * offset behind the entry name. If the entry stores a filetype value, then it
68
+ * sits between the name and the inode number. The actual inode numbers can
69
+ * come in two formats as well, either 4 bytes or 8 bytes wide.
70
+ */
71
+xfs_ino_t
72
+xfs_dir2_sf_get_ino(
73
+ struct xfs_mount *mp,
74
+ struct xfs_dir2_sf_hdr *hdr,
75
+ struct xfs_dir2_sf_entry *sfep)
76
+{
77
+ uint8_t *from = sfep->name + sfep->namelen;
78
+
79
+ if (xfs_sb_version_hasftype(&mp->m_sb))
80
+ from++;
81
+
82
+ if (!hdr->i8count)
83
+ return get_unaligned_be32(from);
84
+ return get_unaligned_be64(from) & XFS_MAXINUMBER;
85
+}
86
+
87
+void
88
+xfs_dir2_sf_put_ino(
89
+ struct xfs_mount *mp,
90
+ struct xfs_dir2_sf_hdr *hdr,
91
+ struct xfs_dir2_sf_entry *sfep,
92
+ xfs_ino_t ino)
93
+{
94
+ uint8_t *to = sfep->name + sfep->namelen;
95
+
96
+ ASSERT(ino <= XFS_MAXINUMBER);
97
+
98
+ if (xfs_sb_version_hasftype(&mp->m_sb))
99
+ to++;
100
+
101
+ if (hdr->i8count)
102
+ put_unaligned_be64(ino, to);
103
+ else
104
+ put_unaligned_be32(ino, to);
105
+}
106
+
107
+xfs_ino_t
108
+xfs_dir2_sf_get_parent_ino(
109
+ struct xfs_dir2_sf_hdr *hdr)
110
+{
111
+ if (!hdr->i8count)
112
+ return get_unaligned_be32(hdr->parent);
113
+ return get_unaligned_be64(hdr->parent) & XFS_MAXINUMBER;
114
+}
115
+
116
+void
117
+xfs_dir2_sf_put_parent_ino(
118
+ struct xfs_dir2_sf_hdr *hdr,
119
+ xfs_ino_t ino)
120
+{
121
+ ASSERT(ino <= XFS_MAXINUMBER);
122
+
123
+ if (hdr->i8count)
124
+ put_unaligned_be64(ino, hdr->parent);
125
+ else
126
+ put_unaligned_be32(ino, hdr->parent);
127
+}
128
+
129
+/*
130
+ * The file type field is stored at the end of the name for filetype enabled
131
+ * shortform directories, or not at all otherwise.
132
+ */
133
+uint8_t
134
+xfs_dir2_sf_get_ftype(
135
+ struct xfs_mount *mp,
136
+ struct xfs_dir2_sf_entry *sfep)
137
+{
138
+ if (xfs_sb_version_hasftype(&mp->m_sb)) {
139
+ uint8_t ftype = sfep->name[sfep->namelen];
140
+
141
+ if (ftype < XFS_DIR3_FT_MAX)
142
+ return ftype;
143
+ }
144
+
145
+ return XFS_DIR3_FT_UNKNOWN;
146
+}
147
+
148
+void
149
+xfs_dir2_sf_put_ftype(
150
+ struct xfs_mount *mp,
151
+ struct xfs_dir2_sf_entry *sfep,
152
+ uint8_t ftype)
153
+{
154
+ ASSERT(ftype < XFS_DIR3_FT_MAX);
155
+
156
+ if (xfs_sb_version_hasftype(&mp->m_sb))
157
+ sfep->name[sfep->namelen] = ftype;
158
+}
42159
43160 /*
44161 * Given a block directory (dp/block), calculate its size as a shortform (sf)
....@@ -128,7 +245,7 @@
128245 */
129246 sfhp->count = count;
130247 sfhp->i8count = i8count;
131
- dp->d_ops->sf_put_parent_ino(sfhp, parent);
248
+ xfs_dir2_sf_put_parent_ino(sfhp, parent);
132249 return size;
133250 }
134251
....@@ -138,64 +255,48 @@
138255 */
139256 int /* error */
140257 xfs_dir2_block_to_sf(
141
- xfs_da_args_t *args, /* operation arguments */
258
+ struct xfs_da_args *args, /* operation arguments */
142259 struct xfs_buf *bp,
143260 int size, /* shortform directory size */
144
- xfs_dir2_sf_hdr_t *sfhp) /* shortform directory hdr */
261
+ struct xfs_dir2_sf_hdr *sfhp) /* shortform directory hdr */
145262 {
146
- xfs_dir2_data_hdr_t *hdr; /* block header */
147
- xfs_dir2_data_entry_t *dep; /* data entry pointer */
148
- xfs_inode_t *dp; /* incore directory inode */
149
- xfs_dir2_data_unused_t *dup; /* unused data pointer */
150
- char *endptr; /* end of data entries */
263
+ struct xfs_inode *dp = args->dp;
264
+ struct xfs_mount *mp = dp->i_mount;
151265 int error; /* error return value */
152266 int logflags; /* inode logging flags */
153
- xfs_mount_t *mp; /* filesystem mount point */
154
- char *ptr; /* current data pointer */
155
- xfs_dir2_sf_entry_t *sfep; /* shortform entry */
156
- xfs_dir2_sf_hdr_t *sfp; /* shortform directory header */
157
- xfs_dir2_sf_hdr_t *dst; /* temporary data buffer */
267
+ struct xfs_dir2_sf_entry *sfep; /* shortform entry */
268
+ struct xfs_dir2_sf_hdr *sfp; /* shortform directory header */
269
+ unsigned int offset = args->geo->data_entry_offset;
270
+ unsigned int end;
158271
159272 trace_xfs_dir2_block_to_sf(args);
160273
161
- dp = args->dp;
162
- mp = dp->i_mount;
163
-
164274 /*
165
- * allocate a temporary destination buffer the size of the inode
166
- * to format the data into. Once we have formatted the data, we
167
- * can free the block and copy the formatted data into the inode literal
168
- * area.
275
+ * Allocate a temporary destination buffer the size of the inode to
276
+ * format the data into. Once we have formatted the data, we can free
277
+ * the block and copy the formatted data into the inode literal area.
169278 */
170
- dst = kmem_alloc(mp->m_sb.sb_inodesize, KM_SLEEP);
171
- hdr = bp->b_addr;
172
-
173
- /*
174
- * Copy the header into the newly allocate local space.
175
- */
176
- sfp = (xfs_dir2_sf_hdr_t *)dst;
279
+ sfp = kmem_alloc(mp->m_sb.sb_inodesize, 0);
177280 memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
178281
179282 /*
180
- * Set up to loop over the block's entries.
283
+ * Loop over the active and unused entries. Stop when we reach the
284
+ * leaf/tail portion of the block.
181285 */
182
- ptr = (char *)dp->d_ops->data_entry_p(hdr);
183
- endptr = xfs_dir3_data_endp(args->geo, hdr);
286
+ end = xfs_dir3_data_end_offset(args->geo, bp->b_addr);
184287 sfep = xfs_dir2_sf_firstentry(sfp);
185
- /*
186
- * Loop over the active and unused entries.
187
- * Stop when we reach the leaf/tail portion of the block.
188
- */
189
- while (ptr < endptr) {
288
+ while (offset < end) {
289
+ struct xfs_dir2_data_unused *dup = bp->b_addr + offset;
290
+ struct xfs_dir2_data_entry *dep = bp->b_addr + offset;
291
+
190292 /*
191293 * If it's unused, just skip over it.
192294 */
193
- dup = (xfs_dir2_data_unused_t *)ptr;
194295 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
195
- ptr += be16_to_cpu(dup->length);
296
+ offset += be16_to_cpu(dup->length);
196297 continue;
197298 }
198
- dep = (xfs_dir2_data_entry_t *)ptr;
299
+
199300 /*
200301 * Skip .
201302 */
....@@ -207,24 +308,22 @@
207308 else if (dep->namelen == 2 &&
208309 dep->name[0] == '.' && dep->name[1] == '.')
209310 ASSERT(be64_to_cpu(dep->inumber) ==
210
- dp->d_ops->sf_get_parent_ino(sfp));
311
+ xfs_dir2_sf_get_parent_ino(sfp));
211312 /*
212313 * Normal entry, copy it into shortform.
213314 */
214315 else {
215316 sfep->namelen = dep->namelen;
216
- xfs_dir2_sf_put_offset(sfep,
217
- (xfs_dir2_data_aoff_t)
218
- ((char *)dep - (char *)hdr));
317
+ xfs_dir2_sf_put_offset(sfep, offset);
219318 memcpy(sfep->name, dep->name, dep->namelen);
220
- dp->d_ops->sf_put_ino(sfp, sfep,
319
+ xfs_dir2_sf_put_ino(mp, sfp, sfep,
221320 be64_to_cpu(dep->inumber));
222
- dp->d_ops->sf_put_ftype(sfep,
223
- dp->d_ops->data_get_ftype(dep));
321
+ xfs_dir2_sf_put_ftype(mp, sfep,
322
+ xfs_dir2_data_get_ftype(mp, dep));
224323
225
- sfep = dp->d_ops->sf_nextentry(sfp, sfep);
324
+ sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
226325 }
227
- ptr += dp->d_ops->data_entsize(dep->namelen);
326
+ offset += xfs_dir2_data_entsize(mp, dep->namelen);
228327 }
229328 ASSERT((char *)sfep - (char *)sfp == size);
230329
....@@ -243,15 +342,15 @@
243342 * Convert the inode to local format and copy the data in.
244343 */
245344 ASSERT(dp->i_df.if_bytes == 0);
246
- xfs_init_local_fork(dp, XFS_DATA_FORK, dst, size);
247
- dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
345
+ xfs_init_local_fork(dp, XFS_DATA_FORK, sfp, size);
346
+ dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
248347 dp->i_d.di_size = size;
249348
250349 logflags |= XFS_ILOG_DDATA;
251350 xfs_dir2_sf_check(args);
252351 out:
253352 xfs_trans_log_inode(args->trans, dp, logflags);
254
- kmem_free(dst);
353
+ kmem_free(sfp);
255354 return error;
256355 }
257356
....@@ -280,13 +379,7 @@
280379 ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT);
281380 dp = args->dp;
282381 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
283
- /*
284
- * Make sure the shortform value has some of its header.
285
- */
286
- if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
287
- ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
288
- return -EIO;
289
- }
382
+ ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
290383 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
291384 ASSERT(dp->i_df.if_u1.if_data != NULL);
292385 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
....@@ -294,7 +387,7 @@
294387 /*
295388 * Compute entry (and change in) size.
296389 */
297
- incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen);
390
+ incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->namelen);
298391 objchange = 0;
299392
300393 /*
....@@ -367,18 +460,17 @@
367460 xfs_dir2_data_aoff_t offset, /* offset to use for new ent */
368461 int new_isize) /* new directory size */
369462 {
463
+ struct xfs_inode *dp = args->dp;
464
+ struct xfs_mount *mp = dp->i_mount;
370465 int byteoff; /* byte offset in sf dir */
371
- xfs_inode_t *dp; /* incore directory inode */
372466 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */
373
-
374
- dp = args->dp;
375467
376468 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
377469 byteoff = (int)((char *)sfep - (char *)sfp);
378470 /*
379471 * Grow the in-inode space.
380472 */
381
- xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->namelen),
473
+ xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->namelen),
382474 XFS_DATA_FORK);
383475 /*
384476 * Need to set up again due to realloc of the inode data.
....@@ -391,8 +483,8 @@
391483 sfep->namelen = args->namelen;
392484 xfs_dir2_sf_put_offset(sfep, offset);
393485 memcpy(sfep->name, args->name, sfep->namelen);
394
- dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
395
- dp->d_ops->sf_put_ftype(sfep, args->filetype);
486
+ xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
487
+ xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
396488
397489 /*
398490 * Update the header and inode.
....@@ -419,9 +511,10 @@
419511 int objchange, /* changing inode number size */
420512 int new_isize) /* new directory size */
421513 {
514
+ struct xfs_inode *dp = args->dp;
515
+ struct xfs_mount *mp = dp->i_mount;
422516 int add_datasize; /* data size need for new ent */
423517 char *buf; /* buffer for old */
424
- xfs_inode_t *dp; /* incore directory inode */
425518 int eof; /* reached end of old dir */
426519 int nbytes; /* temp for byte copies */
427520 xfs_dir2_data_aoff_t new_offset; /* next offset value */
....@@ -435,11 +528,9 @@
435528 /*
436529 * Copy the old directory to the stack buffer.
437530 */
438
- dp = args->dp;
439
-
440531 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
441532 old_isize = (int)dp->i_d.di_size;
442
- buf = kmem_alloc(old_isize, KM_SLEEP);
533
+ buf = kmem_alloc(old_isize, 0);
443534 oldsfp = (xfs_dir2_sf_hdr_t *)buf;
444535 memcpy(oldsfp, sfp, old_isize);
445536 /*
....@@ -447,13 +538,13 @@
447538 * to insert the new entry.
448539 * If it's going to end up at the end then oldsfep will point there.
449540 */
450
- for (offset = dp->d_ops->data_first_offset,
541
+ for (offset = args->geo->data_first_offset,
451542 oldsfep = xfs_dir2_sf_firstentry(oldsfp),
452
- add_datasize = dp->d_ops->data_entsize(args->namelen),
543
+ add_datasize = xfs_dir2_data_entsize(mp, args->namelen),
453544 eof = (char *)oldsfep == &buf[old_isize];
454545 !eof;
455
- offset = new_offset + dp->d_ops->data_entsize(oldsfep->namelen),
456
- oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep),
546
+ offset = new_offset + xfs_dir2_data_entsize(mp, oldsfep->namelen),
547
+ oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep),
457548 eof = (char *)oldsfep == &buf[old_isize]) {
458549 new_offset = xfs_dir2_sf_get_offset(oldsfep);
459550 if (offset + add_datasize <= new_offset)
....@@ -482,8 +573,8 @@
482573 sfep->namelen = args->namelen;
483574 xfs_dir2_sf_put_offset(sfep, offset);
484575 memcpy(sfep->name, args->name, sfep->namelen);
485
- dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
486
- dp->d_ops->sf_put_ftype(sfep, args->filetype);
576
+ xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
577
+ xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
487578 sfp->count++;
488579 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
489580 sfp->i8count++;
....@@ -491,7 +582,7 @@
491582 * If there's more left to copy, do that.
492583 */
493584 if (!eof) {
494
- sfep = dp->d_ops->sf_nextentry(sfp, sfep);
585
+ sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
495586 memcpy(sfep, oldsfep, old_isize - nbytes);
496587 }
497588 kmem_free(buf);
....@@ -513,7 +604,8 @@
513604 xfs_dir2_sf_entry_t **sfepp, /* out(1): new entry ptr */
514605 xfs_dir2_data_aoff_t *offsetp) /* out(1): new offset */
515606 {
516
- xfs_inode_t *dp; /* incore directory inode */
607
+ struct xfs_inode *dp = args->dp;
608
+ struct xfs_mount *mp = dp->i_mount;
517609 int holefit; /* found hole it will fit in */
518610 int i; /* entry number */
519611 xfs_dir2_data_aoff_t offset; /* data block offset */
....@@ -522,11 +614,9 @@
522614 int size; /* entry's data size */
523615 int used; /* data bytes used */
524616
525
- dp = args->dp;
526
-
527617 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
528
- size = dp->d_ops->data_entsize(args->namelen);
529
- offset = dp->d_ops->data_first_offset;
618
+ size = xfs_dir2_data_entsize(mp, args->namelen);
619
+ offset = args->geo->data_first_offset;
530620 sfep = xfs_dir2_sf_firstentry(sfp);
531621 holefit = 0;
532622 /*
....@@ -538,8 +628,8 @@
538628 if (!holefit)
539629 holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
540630 offset = xfs_dir2_sf_get_offset(sfep) +
541
- dp->d_ops->data_entsize(sfep->namelen);
542
- sfep = dp->d_ops->sf_nextentry(sfp, sfep);
631
+ xfs_dir2_data_entsize(mp, sfep->namelen);
632
+ sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
543633 }
544634 /*
545635 * Calculate data bytes used excluding the new entry, if this
....@@ -581,7 +671,8 @@
581671 xfs_dir2_sf_check(
582672 xfs_da_args_t *args) /* operation arguments */
583673 {
584
- xfs_inode_t *dp; /* incore directory inode */
674
+ struct xfs_inode *dp = args->dp;
675
+ struct xfs_mount *mp = dp->i_mount;
585676 int i; /* entry number */
586677 int i8count; /* number of big inode#s */
587678 xfs_ino_t ino; /* entry inode number */
....@@ -589,23 +680,21 @@
589680 xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */
590681 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */
591682
592
- dp = args->dp;
593
-
594683 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
595
- offset = dp->d_ops->data_first_offset;
596
- ino = dp->d_ops->sf_get_parent_ino(sfp);
684
+ offset = args->geo->data_first_offset;
685
+ ino = xfs_dir2_sf_get_parent_ino(sfp);
597686 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
598687
599688 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
600689 i < sfp->count;
601
- i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
690
+ i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
602691 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
603
- ino = dp->d_ops->sf_get_ino(sfp, sfep);
692
+ ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
604693 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
605694 offset =
606695 xfs_dir2_sf_get_offset(sfep) +
607
- dp->d_ops->data_entsize(sfep->namelen);
608
- ASSERT(dp->d_ops->sf_get_ftype(sfep) < XFS_DIR3_FT_MAX);
696
+ xfs_dir2_data_entsize(mp, sfep->namelen);
697
+ ASSERT(xfs_dir2_sf_get_ftype(mp, sfep) < XFS_DIR3_FT_MAX);
609698 }
610699 ASSERT(i8count == sfp->i8count);
611700 ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);
....@@ -621,28 +710,21 @@
621710 struct xfs_inode *ip)
622711 {
623712 struct xfs_mount *mp = ip->i_mount;
713
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
624714 struct xfs_dir2_sf_hdr *sfp;
625715 struct xfs_dir2_sf_entry *sfep;
626716 struct xfs_dir2_sf_entry *next_sfep;
627717 char *endp;
628
- const struct xfs_dir_ops *dops;
629
- struct xfs_ifork *ifp;
630718 xfs_ino_t ino;
631719 int i;
632720 int i8count;
633721 int offset;
634
- int size;
722
+ int64_t size;
635723 int error;
636724 uint8_t filetype;
637725
638
- ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL);
639
- /*
640
- * xfs_iread calls us before xfs_setup_inode sets up ip->d_ops,
641
- * so we can only trust the mountpoint to have the right pointer.
642
- */
643
- dops = xfs_dir_get_ops(mp, NULL);
726
+ ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
644727
645
- ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
646728 sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data;
647729 size = ifp->if_bytes;
648730
....@@ -656,12 +738,12 @@
656738 endp = (char *)sfp + size;
657739
658740 /* Check .. entry */
659
- ino = dops->sf_get_parent_ino(sfp);
741
+ ino = xfs_dir2_sf_get_parent_ino(sfp);
660742 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
661743 error = xfs_dir_ino_validate(mp, ino);
662744 if (error)
663745 return __this_address;
664
- offset = dops->data_first_offset;
746
+ offset = mp->m_dir_geo->data_first_offset;
665747
666748 /* Check all reported entries */
667749 sfep = xfs_dir2_sf_firstentry(sfp);
....@@ -683,7 +765,7 @@
683765 * within the data buffer. The next entry starts after the
684766 * name component, so nextentry is an acceptable test.
685767 */
686
- next_sfep = dops->sf_nextentry(sfp, sfep);
768
+ next_sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
687769 if (endp < (char *)next_sfep)
688770 return __this_address;
689771
....@@ -692,19 +774,19 @@
692774 return __this_address;
693775
694776 /* Check the inode number. */
695
- ino = dops->sf_get_ino(sfp, sfep);
777
+ ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
696778 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
697779 error = xfs_dir_ino_validate(mp, ino);
698780 if (error)
699781 return __this_address;
700782
701783 /* Check the file type. */
702
- filetype = dops->sf_get_ftype(sfep);
784
+ filetype = xfs_dir2_sf_get_ftype(mp, sfep);
703785 if (filetype >= XFS_DIR3_FT_MAX)
704786 return __this_address;
705787
706788 offset = xfs_dir2_sf_get_offset(sfep) +
707
- dops->data_entsize(sfep->namelen);
789
+ xfs_dir2_data_entsize(mp, sfep->namelen);
708790
709791 sfep = next_sfep;
710792 }
....@@ -744,9 +826,9 @@
744826 * If it's currently a zero-length extent file,
745827 * convert it to local format.
746828 */
747
- if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) {
829
+ if (dp->i_df.if_format == XFS_DINODE_FMT_EXTENTS) {
748830 dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */
749
- dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
831
+ dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
750832 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
751833 dp->i_df.if_flags |= XFS_IFINLINE;
752834 }
....@@ -766,7 +848,7 @@
766848 /*
767849 * Now can put in the inode number, since i8count is set.
768850 */
769
- dp->d_ops->sf_put_parent_ino(sfp, pino);
851
+ xfs_dir2_sf_put_parent_ino(sfp, pino);
770852 sfp->count = 0;
771853 dp->i_d.di_size = size;
772854 xfs_dir2_sf_check(args);
....@@ -782,7 +864,8 @@
782864 xfs_dir2_sf_lookup(
783865 xfs_da_args_t *args) /* operation arguments */
784866 {
785
- xfs_inode_t *dp; /* incore directory inode */
867
+ struct xfs_inode *dp = args->dp;
868
+ struct xfs_mount *mp = dp->i_mount;
786869 int i; /* entry index */
787870 int error;
788871 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */
....@@ -793,16 +876,9 @@
793876 trace_xfs_dir2_sf_lookup(args);
794877
795878 xfs_dir2_sf_check(args);
796
- dp = args->dp;
797879
798880 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
799
- /*
800
- * Bail out if the directory is way too short.
801
- */
802
- if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
803
- ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
804
- return -EIO;
805
- }
881
+ ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
806882 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
807883 ASSERT(dp->i_df.if_u1.if_data != NULL);
808884 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
....@@ -821,7 +897,7 @@
821897 */
822898 if (args->namelen == 2 &&
823899 args->name[0] == '.' && args->name[1] == '.') {
824
- args->inumber = dp->d_ops->sf_get_parent_ino(sfp);
900
+ args->inumber = xfs_dir2_sf_get_parent_ino(sfp);
825901 args->cmpresult = XFS_CMP_EXACT;
826902 args->filetype = XFS_DIR3_FT_DIR;
827903 return -EEXIST;
....@@ -831,18 +907,17 @@
831907 */
832908 ci_sfep = NULL;
833909 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
834
- i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
910
+ i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
835911 /*
836912 * Compare name and if it's an exact match, return the inode
837913 * number. If it's the first case-insensitive match, store the
838914 * inode number and continue looking for an exact match.
839915 */
840
- cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name,
841
- sfep->namelen);
916
+ cmp = xfs_dir2_compname(args, sfep->name, sfep->namelen);
842917 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
843918 args->cmpresult = cmp;
844
- args->inumber = dp->d_ops->sf_get_ino(sfp, sfep);
845
- args->filetype = dp->d_ops->sf_get_ftype(sfep);
919
+ args->inumber = xfs_dir2_sf_get_ino(mp, sfp, sfep);
920
+ args->filetype = xfs_dir2_sf_get_ftype(mp, sfep);
846921 if (cmp == XFS_CMP_EXACT)
847922 return -EEXIST;
848923 ci_sfep = sfep;
....@@ -867,8 +942,9 @@
867942 xfs_dir2_sf_removename(
868943 xfs_da_args_t *args)
869944 {
945
+ struct xfs_inode *dp = args->dp;
946
+ struct xfs_mount *mp = dp->i_mount;
870947 int byteoff; /* offset of removed entry */
871
- xfs_inode_t *dp; /* incore directory inode */
872948 int entsize; /* this entry's size */
873949 int i; /* shortform entry index */
874950 int newsize; /* new inode size */
....@@ -878,17 +954,9 @@
878954
879955 trace_xfs_dir2_sf_removename(args);
880956
881
- dp = args->dp;
882
-
883957 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
884958 oldsize = (int)dp->i_d.di_size;
885
- /*
886
- * Bail out if the directory is way too short.
887
- */
888
- if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) {
889
- ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
890
- return -EIO;
891
- }
959
+ ASSERT(oldsize >= offsetof(struct xfs_dir2_sf_hdr, parent));
892960 ASSERT(dp->i_df.if_bytes == oldsize);
893961 ASSERT(dp->i_df.if_u1.if_data != NULL);
894962 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
....@@ -898,10 +966,10 @@
898966 * Find the one we're deleting.
899967 */
900968 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
901
- i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
969
+ i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
902970 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
903971 XFS_CMP_EXACT) {
904
- ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) ==
972
+ ASSERT(xfs_dir2_sf_get_ino(mp, sfp, sfep) ==
905973 args->inumber);
906974 break;
907975 }
....@@ -915,7 +983,7 @@
915983 * Calculate sizes.
916984 */
917985 byteoff = (int)((char *)sfep - (char *)sfp);
918
- entsize = dp->d_ops->sf_entsize(sfp, args->namelen);
986
+ entsize = xfs_dir2_sf_entsize(mp, sfp, args->namelen);
919987 newsize = oldsize - entsize;
920988 /*
921989 * Copy the part if any after the removed entry, sliding it down.
....@@ -948,13 +1016,35 @@
9481016 }
9491017
9501018 /*
1019
+ * Check whether the sf dir replace operation need more blocks.
1020
+ */
1021
+static bool
1022
+xfs_dir2_sf_replace_needblock(
1023
+ struct xfs_inode *dp,
1024
+ xfs_ino_t inum)
1025
+{
1026
+ int newsize;
1027
+ struct xfs_dir2_sf_hdr *sfp;
1028
+
1029
+ if (dp->i_df.if_format != XFS_DINODE_FMT_LOCAL)
1030
+ return false;
1031
+
1032
+ sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data;
1033
+ newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF;
1034
+
1035
+ return inum > XFS_DIR2_MAX_SHORT_INUM &&
1036
+ sfp->i8count == 0 && newsize > XFS_IFORK_DSIZE(dp);
1037
+}
1038
+
1039
+/*
9511040 * Replace the inode number of an entry in a shortform directory.
9521041 */
9531042 int /* error */
9541043 xfs_dir2_sf_replace(
9551044 xfs_da_args_t *args) /* operation arguments */
9561045 {
957
- xfs_inode_t *dp; /* incore directory inode */
1046
+ struct xfs_inode *dp = args->dp;
1047
+ struct xfs_mount *mp = dp->i_mount;
9581048 int i; /* entry index */
9591049 xfs_ino_t ino=0; /* entry old inode number */
9601050 int i8elevated; /* sf_toino8 set i8count=1 */
....@@ -963,16 +1053,8 @@
9631053
9641054 trace_xfs_dir2_sf_replace(args);
9651055
966
- dp = args->dp;
967
-
9681056 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
969
- /*
970
- * Bail out if the shortform directory is way too small.
971
- */
972
- if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
973
- ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
974
- return -EIO;
975
- }
1057
+ ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
9761058 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
9771059 ASSERT(dp->i_df.if_u1.if_data != NULL);
9781060 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
....@@ -983,17 +1065,14 @@
9831065 */
9841066 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
9851067 int error; /* error return value */
986
- int newsize; /* new inode size */
9871068
988
- newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF;
9891069 /*
9901070 * Won't fit as shortform, convert to block then do replace.
9911071 */
992
- if (newsize > XFS_IFORK_DSIZE(dp)) {
1072
+ if (xfs_dir2_sf_replace_needblock(dp, args->inumber)) {
9931073 error = xfs_dir2_sf_to_block(args);
994
- if (error) {
1074
+ if (error)
9951075 return error;
996
- }
9971076 return xfs_dir2_block_replace(args);
9981077 }
9991078 /*
....@@ -1011,22 +1090,23 @@
10111090 */
10121091 if (args->namelen == 2 &&
10131092 args->name[0] == '.' && args->name[1] == '.') {
1014
- ino = dp->d_ops->sf_get_parent_ino(sfp);
1093
+ ino = xfs_dir2_sf_get_parent_ino(sfp);
10151094 ASSERT(args->inumber != ino);
1016
- dp->d_ops->sf_put_parent_ino(sfp, args->inumber);
1095
+ xfs_dir2_sf_put_parent_ino(sfp, args->inumber);
10171096 }
10181097 /*
10191098 * Normal entry, look for the name.
10201099 */
10211100 else {
10221101 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
1023
- i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
1102
+ i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
10241103 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
10251104 XFS_CMP_EXACT) {
1026
- ino = dp->d_ops->sf_get_ino(sfp, sfep);
1105
+ ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
10271106 ASSERT(args->inumber != ino);
1028
- dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
1029
- dp->d_ops->sf_put_ftype(sfep, args->filetype);
1107
+ xfs_dir2_sf_put_ino(mp, sfp, sfep,
1108
+ args->inumber);
1109
+ xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
10301110 break;
10311111 }
10321112 }
....@@ -1079,8 +1159,9 @@
10791159 xfs_dir2_sf_toino4(
10801160 xfs_da_args_t *args) /* operation arguments */
10811161 {
1162
+ struct xfs_inode *dp = args->dp;
1163
+ struct xfs_mount *mp = dp->i_mount;
10821164 char *buf; /* old dir's buffer */
1083
- xfs_inode_t *dp; /* incore directory inode */
10841165 int i; /* entry index */
10851166 int newsize; /* new inode size */
10861167 xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */
....@@ -1091,15 +1172,13 @@
10911172
10921173 trace_xfs_dir2_sf_toino4(args);
10931174
1094
- dp = args->dp;
1095
-
10961175 /*
10971176 * Copy the old directory to the buffer.
10981177 * Then nuke it from the inode, and add the new buffer to the inode.
10991178 * Don't want xfs_idata_realloc copying the data here.
11001179 */
11011180 oldsize = dp->i_df.if_bytes;
1102
- buf = kmem_alloc(oldsize, KM_SLEEP);
1181
+ buf = kmem_alloc(oldsize, 0);
11031182 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
11041183 ASSERT(oldsfp->i8count == 1);
11051184 memcpy(buf, oldsfp, oldsize);
....@@ -1119,21 +1198,22 @@
11191198 */
11201199 sfp->count = oldsfp->count;
11211200 sfp->i8count = 0;
1122
- dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp));
1201
+ xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
11231202 /*
11241203 * Copy the entries field by field.
11251204 */
11261205 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
11271206 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
11281207 i < sfp->count;
1129
- i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep),
1130
- oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) {
1208
+ i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
1209
+ oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
11311210 sfep->namelen = oldsfep->namelen;
11321211 memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
11331212 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1134
- dp->d_ops->sf_put_ino(sfp, sfep,
1135
- dp->d_ops->sf_get_ino(oldsfp, oldsfep));
1136
- dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep));
1213
+ xfs_dir2_sf_put_ino(mp, sfp, sfep,
1214
+ xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
1215
+ xfs_dir2_sf_put_ftype(mp, sfep,
1216
+ xfs_dir2_sf_get_ftype(mp, oldsfep));
11371217 }
11381218 /*
11391219 * Clean up the inode.
....@@ -1152,8 +1232,9 @@
11521232 xfs_dir2_sf_toino8(
11531233 xfs_da_args_t *args) /* operation arguments */
11541234 {
1235
+ struct xfs_inode *dp = args->dp;
1236
+ struct xfs_mount *mp = dp->i_mount;
11551237 char *buf; /* old dir's buffer */
1156
- xfs_inode_t *dp; /* incore directory inode */
11571238 int i; /* entry index */
11581239 int newsize; /* new inode size */
11591240 xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */
....@@ -1164,15 +1245,13 @@
11641245
11651246 trace_xfs_dir2_sf_toino8(args);
11661247
1167
- dp = args->dp;
1168
-
11691248 /*
11701249 * Copy the old directory to the buffer.
11711250 * Then nuke it from the inode, and add the new buffer to the inode.
11721251 * Don't want xfs_idata_realloc copying the data here.
11731252 */
11741253 oldsize = dp->i_df.if_bytes;
1175
- buf = kmem_alloc(oldsize, KM_SLEEP);
1254
+ buf = kmem_alloc(oldsize, 0);
11761255 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
11771256 ASSERT(oldsfp->i8count == 0);
11781257 memcpy(buf, oldsfp, oldsize);
....@@ -1192,21 +1271,22 @@
11921271 */
11931272 sfp->count = oldsfp->count;
11941273 sfp->i8count = 1;
1195
- dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp));
1274
+ xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
11961275 /*
11971276 * Copy the entries field by field.
11981277 */
11991278 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
12001279 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
12011280 i < sfp->count;
1202
- i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep),
1203
- oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) {
1281
+ i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
1282
+ oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
12041283 sfep->namelen = oldsfep->namelen;
12051284 memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
12061285 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1207
- dp->d_ops->sf_put_ino(sfp, sfep,
1208
- dp->d_ops->sf_get_ino(oldsfp, oldsfep));
1209
- dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep));
1286
+ xfs_dir2_sf_put_ino(mp, sfp, sfep,
1287
+ xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
1288
+ xfs_dir2_sf_put_ftype(mp, sfep,
1289
+ xfs_dir2_sf_get_ftype(mp, oldsfep));
12101290 }
12111291 /*
12121292 * Clean up the inode.