diff options
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 39 |
1 files changed, 34 insertions, 5 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index eedd24d0ad2e..0989a2099688 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -475,6 +475,29 @@ different: | |||
475 | } | 475 | } |
476 | 476 | ||
477 | static | 477 | static |
478 | bool nfs_use_readdirplus(struct inode *dir, struct file *filp) | ||
479 | { | ||
480 | if (!nfs_server_capable(dir, NFS_CAP_READDIRPLUS)) | ||
481 | return false; | ||
482 | if (test_and_clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags)) | ||
483 | return true; | ||
484 | if (filp->f_pos == 0) | ||
485 | return true; | ||
486 | return false; | ||
487 | } | ||
488 | |||
489 | /* | ||
490 | * This function is called by the lookup code to request the use of | ||
491 | * readdirplus to accelerate any future lookups in the same | ||
492 | * directory. | ||
493 | */ | ||
494 | static | ||
495 | void nfs_advise_use_readdirplus(struct inode *dir) | ||
496 | { | ||
497 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags); | ||
498 | } | ||
499 | |||
500 | static | ||
478 | void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | 501 | void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) |
479 | { | 502 | { |
480 | struct qstr filename = QSTR_INIT(entry->name, entry->len); | 503 | struct qstr filename = QSTR_INIT(entry->name, entry->len); |
@@ -871,7 +894,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
871 | desc->file = filp; | 894 | desc->file = filp; |
872 | desc->dir_cookie = &dir_ctx->dir_cookie; | 895 | desc->dir_cookie = &dir_ctx->dir_cookie; |
873 | desc->decode = NFS_PROTO(inode)->decode_dirent; | 896 | desc->decode = NFS_PROTO(inode)->decode_dirent; |
874 | desc->plus = NFS_USE_READDIRPLUS(inode); | 897 | desc->plus = nfs_use_readdirplus(inode, filp) ? 1 : 0; |
875 | 898 | ||
876 | nfs_block_sillyrename(dentry); | 899 | nfs_block_sillyrename(dentry); |
877 | res = nfs_revalidate_mapping(inode, filp->f_mapping); | 900 | res = nfs_revalidate_mapping(inode, filp->f_mapping); |
@@ -1111,7 +1134,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1111 | if (!inode) { | 1134 | if (!inode) { |
1112 | if (nfs_neg_need_reval(dir, dentry, nd)) | 1135 | if (nfs_neg_need_reval(dir, dentry, nd)) |
1113 | goto out_bad; | 1136 | goto out_bad; |
1114 | goto out_valid; | 1137 | goto out_valid_noent; |
1115 | } | 1138 | } |
1116 | 1139 | ||
1117 | if (is_bad_inode(inode)) { | 1140 | if (is_bad_inode(inode)) { |
@@ -1140,7 +1163,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1140 | if (fhandle == NULL || fattr == NULL) | 1163 | if (fhandle == NULL || fattr == NULL) |
1141 | goto out_error; | 1164 | goto out_error; |
1142 | 1165 | ||
1143 | error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); | 1166 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
1144 | if (error) | 1167 | if (error) |
1145 | goto out_bad; | 1168 | goto out_bad; |
1146 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) | 1169 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) |
@@ -1153,6 +1176,9 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1153 | out_set_verifier: | 1176 | out_set_verifier: |
1154 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1177 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1155 | out_valid: | 1178 | out_valid: |
1179 | /* Success: notify readdir to use READDIRPLUS */ | ||
1180 | nfs_advise_use_readdirplus(dir); | ||
1181 | out_valid_noent: | ||
1156 | dput(parent); | 1182 | dput(parent); |
1157 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n", | 1183 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n", |
1158 | __func__, dentry->d_parent->d_name.name, | 1184 | __func__, dentry->d_parent->d_name.name, |
@@ -1296,7 +1322,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
1296 | parent = dentry->d_parent; | 1322 | parent = dentry->d_parent; |
1297 | /* Protect against concurrent sillydeletes */ | 1323 | /* Protect against concurrent sillydeletes */ |
1298 | nfs_block_sillyrename(parent); | 1324 | nfs_block_sillyrename(parent); |
1299 | error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); | 1325 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
1300 | if (error == -ENOENT) | 1326 | if (error == -ENOENT) |
1301 | goto no_entry; | 1327 | goto no_entry; |
1302 | if (error < 0) { | 1328 | if (error < 0) { |
@@ -1308,6 +1334,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
1308 | if (IS_ERR(res)) | 1334 | if (IS_ERR(res)) |
1309 | goto out_unblock_sillyrename; | 1335 | goto out_unblock_sillyrename; |
1310 | 1336 | ||
1337 | /* Success: notify readdir to use READDIRPLUS */ | ||
1338 | nfs_advise_use_readdirplus(dir); | ||
1339 | |||
1311 | no_entry: | 1340 | no_entry: |
1312 | res = d_materialise_unique(dentry, inode); | 1341 | res = d_materialise_unique(dentry, inode); |
1313 | if (res != NULL) { | 1342 | if (res != NULL) { |
@@ -1643,7 +1672,7 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, | |||
1643 | if (dentry->d_inode) | 1672 | if (dentry->d_inode) |
1644 | goto out; | 1673 | goto out; |
1645 | if (fhandle->size == 0) { | 1674 | if (fhandle->size == 0) { |
1646 | error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); | 1675 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
1647 | if (error) | 1676 | if (error) |
1648 | goto out_error; | 1677 | goto out_error; |
1649 | } | 1678 | } |