aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-10-29 07:11:46 -0400
committerBen Myers <bpm@sgi.com>2013-10-30 14:37:38 -0400
commit32c5483a8a13a43264809144210ec114dd70b611 (patch)
tree62db2c9a27d98cdc614dea74b3dabbe197d97bf2
parentc963c6193a5adaec58044e238ef23516d04e5a74 (diff)
xfs: abstract the differences in dir2/dir3 via an ops vector
Lots of the dir code now goes through switches to determine what is the correct on-disk format to parse. It generally involves a "xfs_sbversion_hasfoo" check, deferencing the superblock version and feature fields and hence touching several cache lines per operation in the process. Some operations do multiple checks because they nest conditional operations and they don't pass the information in a direct fashion between each other. Hence, add an ops vector to the xfs_inode structure that is configured when the inode is initialised to point to all the correct decode and encoding operations. This will significantly reduce the branchiness and cacheline footprint of the directory object decoding and encoding. This is the first patch in a series of conversion patches. It will introduce the ops structure, the setup of it and add the first operation to the vector. Subsequent patches will convert directory ops one at a time to keep the changes simple and obvious. Just this patch shows the benefit of such an approach on code size. Just converting the two shortform dir operations as this patch does decreases the built binary size by ~1500 bytes: $ size fs/xfs/xfs.o.orig fs/xfs/xfs.o.p1 text data bss dec hex filename 794490 96802 1096 892388 d9de4 fs/xfs/xfs.o.orig 792986 96802 1096 890884 d9804 fs/xfs/xfs.o.p1 $ That's a significant decrease in the instruction cache footprint of the directory code for such a simple change, and indicates that this approach is definitely worth pursuing further. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ben Myers <bpm@sgi.com>
-rw-r--r--fs/xfs/Makefile1
-rw-r--r--fs/xfs/xfs_da_btree.h1
-rw-r--r--fs/xfs/xfs_da_format.c85
-rw-r--r--fs/xfs/xfs_da_format.h26
-rw-r--r--fs/xfs/xfs_dir2.c7
-rw-r--r--fs/xfs/xfs_dir2.h14
-rw-r--r--fs/xfs/xfs_dir2_block.c2
-rw-r--r--fs/xfs/xfs_dir2_readdir.c4
-rw-r--r--fs/xfs/xfs_dir2_sf.c31
-rw-r--r--fs/xfs/xfs_inode.h3
-rw-r--r--fs/xfs/xfs_iops.c1
-rw-r--r--fs/xfs/xfs_mount.h2
12 files changed, 132 insertions, 45 deletions
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 33a69fabfd83..c21f43506661 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -66,6 +66,7 @@ xfs-y += xfs_alloc.o \
66 xfs_bmap_btree.o \ 66 xfs_bmap_btree.o \
67 xfs_btree.o \ 67 xfs_btree.o \
68 xfs_da_btree.o \ 68 xfs_da_btree.o \
69 xfs_da_format.o \
69 xfs_dir2.o \ 70 xfs_dir2.o \
70 xfs_dir2_block.o \ 71 xfs_dir2_block.o \
71 xfs_dir2_data.o \ 72 xfs_dir2_data.o \
diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h
index e492dcadd032..6e95ea79f5d7 100644
--- a/fs/xfs/xfs_da_btree.h
+++ b/fs/xfs/xfs_da_btree.h
@@ -23,6 +23,7 @@ struct xfs_bmap_free;
23struct xfs_inode; 23struct xfs_inode;
24struct xfs_trans; 24struct xfs_trans;
25struct zone; 25struct zone;
26struct xfs_dir_ops;
26 27
27/*======================================================================== 28/*========================================================================
28 * Btree searching and modification structure definitions. 29 * Btree searching and modification structure definitions.
diff --git a/fs/xfs/xfs_da_format.c b/fs/xfs/xfs_da_format.c
new file mode 100644
index 000000000000..982d105d012f
--- /dev/null
+++ b/fs/xfs/xfs_da_format.c
@@ -0,0 +1,85 @@
1/*
2 * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc.
3 * Copyright (c) 2013 Red Hat, Inc.
4 * All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include "xfs.h"
20#include "xfs_fs.h"
21#include "xfs_format.h"
22#include "xfs_log_format.h"
23#include "xfs_trans_resv.h"
24#include "xfs_sb.h"
25#include "xfs_ag.h"
26#include "xfs_mount.h"
27#include "xfs_da_format.h"
28#include "xfs_inode.h"
29#include "xfs_dir2.h"
30
31
32static int
33xfs_dir2_sf_entsize(
34 struct xfs_dir2_sf_hdr *hdr,
35 int len)
36{
37 int count = sizeof(struct xfs_dir2_sf_entry); /* namelen + offset */
38
39 count += len; /* name */
40 count += hdr->i8count ? sizeof(xfs_dir2_ino8_t) :
41 sizeof(xfs_dir2_ino4_t); /* ino # */
42 return count;
43}
44
45static int
46xfs_dir3_sf_entsize(
47 struct xfs_dir2_sf_hdr *hdr,
48 int len)
49{
50 return xfs_dir2_sf_entsize(hdr, len) + sizeof(__uint8_t);
51}
52
53static struct xfs_dir2_sf_entry *
54xfs_dir2_sf_nextentry(
55 struct xfs_dir2_sf_hdr *hdr,
56 struct xfs_dir2_sf_entry *sfep)
57{
58 return (struct xfs_dir2_sf_entry *)
59 ((char *)sfep + xfs_dir2_sf_entsize(hdr, sfep->namelen));
60}
61
62static struct xfs_dir2_sf_entry *
63xfs_dir3_sf_nextentry(
64 struct xfs_dir2_sf_hdr *hdr,
65 struct xfs_dir2_sf_entry *sfep)
66{
67 return (struct xfs_dir2_sf_entry *)
68 ((char *)sfep + xfs_dir3_sf_entsize(hdr, sfep->namelen));
69}
70
71
72const struct xfs_dir_ops xfs_dir2_ops = {
73 .sf_entsize = xfs_dir2_sf_entsize,
74 .sf_nextentry = xfs_dir2_sf_nextentry,
75};
76
77const struct xfs_dir_ops xfs_dir2_ftype_ops = {
78 .sf_entsize = xfs_dir3_sf_entsize,
79 .sf_nextentry = xfs_dir3_sf_nextentry,
80};
81
82const struct xfs_dir_ops xfs_dir3_ops = {
83 .sf_entsize = xfs_dir3_sf_entsize,
84 .sf_nextentry = xfs_dir3_sf_nextentry,
85};
diff --git a/fs/xfs/xfs_da_format.h b/fs/xfs/xfs_da_format.h
index 89a1a219c8ff..d54726d0fc10 100644
--- a/fs/xfs/xfs_da_format.h
+++ b/fs/xfs/xfs_da_format.h
@@ -329,32 +329,6 @@ xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr)
329 ((char *)hdr + xfs_dir2_sf_hdr_size(hdr->i8count)); 329 ((char *)hdr + xfs_dir2_sf_hdr_size(hdr->i8count));
330} 330}
331 331
332static inline int
333xfs_dir3_sf_entsize(
334 struct xfs_mount *mp,
335 struct xfs_dir2_sf_hdr *hdr,
336 int len)
337{
338 int count = sizeof(struct xfs_dir2_sf_entry); /* namelen + offset */
339
340 count += len; /* name */
341 count += hdr->i8count ? sizeof(xfs_dir2_ino8_t) :
342 sizeof(xfs_dir2_ino4_t); /* ino # */
343 if (xfs_sb_version_hasftype(&mp->m_sb))
344 count += sizeof(__uint8_t); /* file type */
345 return count;
346}
347
348static inline struct xfs_dir2_sf_entry *
349xfs_dir3_sf_nextentry(
350 struct xfs_mount *mp,
351 struct xfs_dir2_sf_hdr *hdr,
352 struct xfs_dir2_sf_entry *sfep)
353{
354 return (struct xfs_dir2_sf_entry *)
355 ((char *)sfep + xfs_dir3_sf_entsize(mp, hdr, sfep->namelen));
356}
357
358/* 332/*
359 * in dir3 shortform directories, the file type field is stored at a variable 333 * in dir3 shortform directories, the file type field is stored at a variable
360 * offset after the inode number. Because it's only a single byte, endian 334 * offset after the inode number. Because it's only a single byte, endian
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
index 38bf9324302c..7911136453cd 100644
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -112,6 +112,13 @@ xfs_dir_mount(
112 mp->m_dirnameops = &xfs_ascii_ci_nameops; 112 mp->m_dirnameops = &xfs_ascii_ci_nameops;
113 else 113 else
114 mp->m_dirnameops = &xfs_default_nameops; 114 mp->m_dirnameops = &xfs_default_nameops;
115
116 if (xfs_sb_version_hascrc(&mp->m_sb))
117 mp->m_dir_inode_ops = &xfs_dir3_ops;
118 else if (xfs_sb_version_hasftype(&mp->m_sb))
119 mp->m_dir_inode_ops = &xfs_dir2_ftype_ops;
120 else
121 mp->m_dir_inode_ops = &xfs_dir2_ops;
115} 122}
116 123
117/* 124/*
diff --git a/fs/xfs/xfs_dir2.h b/fs/xfs/xfs_dir2.h
index 9910401327d4..1909d9faff71 100644
--- a/fs/xfs/xfs_dir2.h
+++ b/fs/xfs/xfs_dir2.h
@@ -32,6 +32,20 @@ struct xfs_dir2_data_unused;
32extern struct xfs_name xfs_name_dotdot; 32extern struct xfs_name xfs_name_dotdot;
33 33
34/* 34/*
35 * directory operations vector for encode/decode routines
36 */
37struct xfs_dir_ops {
38 int (*sf_entsize)(struct xfs_dir2_sf_hdr *hdr, int len);
39 struct xfs_dir2_sf_entry *
40 (*sf_nextentry)(struct xfs_dir2_sf_hdr *hdr,
41 struct xfs_dir2_sf_entry *sfep);
42};
43
44extern const struct xfs_dir_ops xfs_dir2_ops;
45extern const struct xfs_dir_ops xfs_dir2_ftype_ops;
46extern const struct xfs_dir_ops xfs_dir3_ops;
47
48/*
35 * Generic directory interface routines 49 * Generic directory interface routines
36 */ 50 */
37extern void xfs_dir_startup(void); 51extern void xfs_dir_startup(void);
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index 9f3f83a5e2da..9d86b6f9e80f 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -1240,7 +1240,7 @@ xfs_dir2_sf_to_block(
1240 if (++i == sfp->count) 1240 if (++i == sfp->count)
1241 sfep = NULL; 1241 sfep = NULL;
1242 else 1242 else
1243 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep); 1243 sfep = dp->d_ops->sf_nextentry(sfp, sfep);
1244 } 1244 }
1245 /* Done with the temporary buffer */ 1245 /* Done with the temporary buffer */
1246 kmem_free(sfp); 1246 kmem_free(sfp);
diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c
index 45c9ce8cdb28..80333055df34 100644
--- a/fs/xfs/xfs_dir2_readdir.c
+++ b/fs/xfs/xfs_dir2_readdir.c
@@ -153,7 +153,7 @@ xfs_dir2_sf_getdents(
153 xfs_dir2_sf_get_offset(sfep)); 153 xfs_dir2_sf_get_offset(sfep));
154 154
155 if (ctx->pos > off) { 155 if (ctx->pos > off) {
156 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep); 156 sfep = dp->d_ops->sf_nextentry(sfp, sfep);
157 continue; 157 continue;
158 } 158 }
159 159
@@ -163,7 +163,7 @@ xfs_dir2_sf_getdents(
163 if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino, 163 if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino,
164 xfs_dir3_get_dtype(mp, filetype))) 164 xfs_dir3_get_dtype(mp, filetype)))
165 return 0; 165 return 0;
166 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep); 166 sfep = dp->d_ops->sf_nextentry(sfp, sfep);
167 } 167 }
168 168
169 ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) & 169 ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
index 8811ee5eaec6..73881c9f40d6 100644
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -336,7 +336,7 @@ xfs_dir2_block_to_sf(
336 xfs_dir3_sfe_put_ftype(mp, sfp, sfep, 336 xfs_dir3_sfe_put_ftype(mp, sfp, sfep,
337 xfs_dir3_dirent_get_ftype(mp, dep)); 337 xfs_dir3_dirent_get_ftype(mp, dep));
338 338
339 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep); 339 sfep = dp->d_ops->sf_nextentry(sfp, sfep);
340 } 340 }
341 ptr += xfs_dir3_data_entsize(mp, dep->namelen); 341 ptr += xfs_dir3_data_entsize(mp, dep->namelen);
342 } 342 }
@@ -389,7 +389,7 @@ xfs_dir2_sf_addname(
389 /* 389 /*
390 * Compute entry (and change in) size. 390 * Compute entry (and change in) size.
391 */ 391 */
392 add_entsize = xfs_dir3_sf_entsize(dp->i_mount, sfp, args->namelen); 392 add_entsize = dp->d_ops->sf_entsize(sfp, args->namelen);
393 incr_isize = add_entsize; 393 incr_isize = add_entsize;
394 objchange = 0; 394 objchange = 0;
395#if XFS_BIG_INUMS 395#if XFS_BIG_INUMS
@@ -483,8 +483,7 @@ xfs_dir2_sf_addname_easy(
483 /* 483 /*
484 * Grow the in-inode space. 484 * Grow the in-inode space.
485 */ 485 */
486 xfs_idata_realloc(dp, 486 xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->namelen),
487 xfs_dir3_sf_entsize(dp->i_mount, sfp, args->namelen),
488 XFS_DATA_FORK); 487 XFS_DATA_FORK);
489 /* 488 /*
490 * Need to set up again due to realloc of the inode data. 489 * Need to set up again due to realloc of the inode data.
@@ -563,7 +562,7 @@ xfs_dir2_sf_addname_hard(
563 eof = (char *)oldsfep == &buf[old_isize]; 562 eof = (char *)oldsfep == &buf[old_isize];
564 !eof; 563 !eof;
565 offset = new_offset + xfs_dir3_data_entsize(mp, oldsfep->namelen), 564 offset = new_offset + xfs_dir3_data_entsize(mp, oldsfep->namelen),
566 oldsfep = xfs_dir3_sf_nextentry(mp, oldsfp, oldsfep), 565 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep),
567 eof = (char *)oldsfep == &buf[old_isize]) { 566 eof = (char *)oldsfep == &buf[old_isize]) {
568 new_offset = xfs_dir2_sf_get_offset(oldsfep); 567 new_offset = xfs_dir2_sf_get_offset(oldsfep);
569 if (offset + add_datasize <= new_offset) 568 if (offset + add_datasize <= new_offset)
@@ -603,7 +602,7 @@ xfs_dir2_sf_addname_hard(
603 * If there's more left to copy, do that. 602 * If there's more left to copy, do that.
604 */ 603 */
605 if (!eof) { 604 if (!eof) {
606 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep); 605 sfep = dp->d_ops->sf_nextentry(sfp, sfep);
607 memcpy(sfep, oldsfep, old_isize - nbytes); 606 memcpy(sfep, oldsfep, old_isize - nbytes);
608 } 607 }
609 kmem_free(buf); 608 kmem_free(buf);
@@ -653,7 +652,7 @@ xfs_dir2_sf_addname_pick(
653 holefit = offset + size <= xfs_dir2_sf_get_offset(sfep); 652 holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
654 offset = xfs_dir2_sf_get_offset(sfep) + 653 offset = xfs_dir2_sf_get_offset(sfep) +
655 xfs_dir3_data_entsize(mp, sfep->namelen); 654 xfs_dir3_data_entsize(mp, sfep->namelen);
656 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep); 655 sfep = dp->d_ops->sf_nextentry(sfp, sfep);
657 } 656 }
658 /* 657 /*
659 * Calculate data bytes used excluding the new entry, if this 658 * Calculate data bytes used excluding the new entry, if this
@@ -719,7 +718,7 @@ xfs_dir2_sf_check(
719 718
720 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); 719 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
721 i < sfp->count; 720 i < sfp->count;
722 i++, sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep)) { 721 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
723 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset); 722 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
724 ino = xfs_dir3_sfe_get_ino(mp, sfp, sfep); 723 ino = xfs_dir3_sfe_get_ino(mp, sfp, sfep);
725 i8count += ino > XFS_DIR2_MAX_SHORT_INUM; 724 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
@@ -848,7 +847,7 @@ xfs_dir2_sf_lookup(
848 */ 847 */
849 ci_sfep = NULL; 848 ci_sfep = NULL;
850 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 849 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
851 i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) { 850 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
852 /* 851 /*
853 * Compare name and if it's an exact match, return the inode 852 * Compare name and if it's an exact match, return the inode
854 * number. If it's the first case-insensitive match, store the 853 * number. If it's the first case-insensitive match, store the
@@ -917,7 +916,7 @@ xfs_dir2_sf_removename(
917 * Find the one we're deleting. 916 * Find the one we're deleting.
918 */ 917 */
919 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 918 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
920 i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) { 919 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
921 if (xfs_da_compname(args, sfep->name, sfep->namelen) == 920 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
922 XFS_CMP_EXACT) { 921 XFS_CMP_EXACT) {
923 ASSERT(xfs_dir3_sfe_get_ino(dp->i_mount, sfp, sfep) == 922 ASSERT(xfs_dir3_sfe_get_ino(dp->i_mount, sfp, sfep) ==
@@ -934,7 +933,7 @@ xfs_dir2_sf_removename(
934 * Calculate sizes. 933 * Calculate sizes.
935 */ 934 */
936 byteoff = (int)((char *)sfep - (char *)sfp); 935 byteoff = (int)((char *)sfep - (char *)sfp);
937 entsize = xfs_dir3_sf_entsize(dp->i_mount, sfp, args->namelen); 936 entsize = dp->d_ops->sf_entsize(sfp, args->namelen);
938 newsize = oldsize - entsize; 937 newsize = oldsize - entsize;
939 /* 938 /*
940 * Copy the part if any after the removed entry, sliding it down. 939 * Copy the part if any after the removed entry, sliding it down.
@@ -1051,7 +1050,7 @@ xfs_dir2_sf_replace(
1051 */ 1050 */
1052 else { 1051 else {
1053 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 1052 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
1054 i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) { 1053 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
1055 if (xfs_da_compname(args, sfep->name, sfep->namelen) == 1054 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
1056 XFS_CMP_EXACT) { 1055 XFS_CMP_EXACT) {
1057#if XFS_BIG_INUMS || defined(DEBUG) 1056#if XFS_BIG_INUMS || defined(DEBUG)
@@ -1172,8 +1171,8 @@ xfs_dir2_sf_toino4(
1172 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), 1171 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1173 oldsfep = xfs_dir2_sf_firstentry(oldsfp); 1172 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1174 i < sfp->count; 1173 i < sfp->count;
1175 i++, sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep), 1174 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep),
1176 oldsfep = xfs_dir3_sf_nextentry(mp, oldsfp, oldsfep)) { 1175 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) {
1177 sfep->namelen = oldsfep->namelen; 1176 sfep->namelen = oldsfep->namelen;
1178 sfep->offset = oldsfep->offset; 1177 sfep->offset = oldsfep->offset;
1179 memcpy(sfep->name, oldsfep->name, sfep->namelen); 1178 memcpy(sfep->name, oldsfep->name, sfep->namelen);
@@ -1251,8 +1250,8 @@ xfs_dir2_sf_toino8(
1251 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), 1250 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1252 oldsfep = xfs_dir2_sf_firstentry(oldsfp); 1251 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1253 i < sfp->count; 1252 i < sfp->count;
1254 i++, sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep), 1253 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep),
1255 oldsfep = xfs_dir3_sf_nextentry(mp, oldsfp, oldsfep)) { 1254 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) {
1256 sfep->namelen = oldsfep->namelen; 1255 sfep->namelen = oldsfep->namelen;
1257 sfep->offset = oldsfep->offset; 1256 sfep->offset = oldsfep->offset;
1258 memcpy(sfep->name, oldsfep->name, sfep->namelen); 1257 memcpy(sfep->name, oldsfep->name, sfep->namelen);
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 66675877f38c..9e6efccbae04 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -49,6 +49,9 @@ typedef struct xfs_inode {
49 xfs_ifork_t *i_afp; /* attribute fork pointer */ 49 xfs_ifork_t *i_afp; /* attribute fork pointer */
50 xfs_ifork_t i_df; /* data fork */ 50 xfs_ifork_t i_df; /* data fork */
51 51
52 /* operations vectors */
53 const struct xfs_dir_ops *d_ops; /* directory ops vector */
54
52 /* Transaction and locking information. */ 55 /* Transaction and locking information. */
53 struct xfs_inode_log_item *i_itemp; /* logging information */ 56 struct xfs_inode_log_item *i_itemp; /* logging information */
54 mrlock_t i_lock; /* inode lock */ 57 mrlock_t i_lock; /* inode lock */
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 718b62b0fe05..0493587ea6bc 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1215,6 +1215,7 @@ xfs_setup_inode(
1215 else 1215 else
1216 inode->i_op = &xfs_dir_inode_operations; 1216 inode->i_op = &xfs_dir_inode_operations;
1217 inode->i_fop = &xfs_dir_file_operations; 1217 inode->i_fop = &xfs_dir_file_operations;
1218 ip->d_ops = ip->i_mount->m_dir_inode_ops;
1218 break; 1219 break;
1219 case S_IFLNK: 1220 case S_IFLNK:
1220 inode->i_op = &xfs_symlink_inode_operations; 1221 inode->i_op = &xfs_symlink_inode_operations;
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 1fa0584b5627..973397f66c6b 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -26,6 +26,7 @@ struct xfs_mru_cache;
26struct xfs_nameops; 26struct xfs_nameops;
27struct xfs_ail; 27struct xfs_ail;
28struct xfs_quotainfo; 28struct xfs_quotainfo;
29struct xfs_dir_ops;
29 30
30#ifdef HAVE_PERCPU_SB 31#ifdef HAVE_PERCPU_SB
31 32
@@ -148,6 +149,7 @@ typedef struct xfs_mount {
148 int m_dir_magicpct; /* 37% of the dir blocksize */ 149 int m_dir_magicpct; /* 37% of the dir blocksize */
149 __uint8_t m_sectbb_log; /* sectlog - BBSHIFT */ 150 __uint8_t m_sectbb_log; /* sectlog - BBSHIFT */
150 const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */ 151 const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */
152 const struct xfs_dir_ops *m_dir_inode_ops; /* vector of dir inode ops */
151 int m_dirblksize; /* directory block sz--bytes */ 153 int m_dirblksize; /* directory block sz--bytes */
152 int m_dirblkfsbs; /* directory block sz--fsbs */ 154 int m_dirblkfsbs; /* directory block sz--fsbs */
153 xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ 155 xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */