diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-11 15:11:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-11 15:11:35 -0400 |
commit | 1466b77a7be75144dee1cb09839be3435854dd0b (patch) | |
tree | 977a0b6c1cd69ff98e5027359bb7de7b8897276a | |
parent | 19d2f8e0fb7bba99cc585d2467e9fa54a84c8557 (diff) | |
parent | eeee245268c951262b861bc1be4e9dc812352499 (diff) |
Merge tag 'nfs-for-3.11-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull second set of NFS client updates from Trond Myklebust:
"This mainly contains some small readdir optimisations that had
dependencies on Al Viro's readdir rewrite. There is also a fix for a
nasty deadlock which surfaced earlier in this merge window.
Highlights include:
- Fix an_rpc pipefs regression that causes a deadlock on mount
- Readdir optimisations by Scott Mayhew and Jeff Layton
- clean up the rpc_pipefs dentry operation setup"
* tag 'nfs-for-3.11-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
SUNRPC: Fix a deadlock in rpc_client_register()
rpc_pipe: rpc_dir_inode_operations can be static
NFS: Allow nfs_updatepage to extend a write under additional circumstances
NFS: Make nfs_readdir revalidate less often
NFS: Make nfs_attribute_cache_expired() non-static
rpc_pipe: set dentry operations at d_alloc time
nfs: set verifier on existing dentries in nfs_prime_dcache
-rw-r--r-- | fs/nfs/dir.c | 6 | ||||
-rw-r--r-- | fs/nfs/inode.c | 2 | ||||
-rw-r--r-- | fs/nfs/write.c | 31 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 1 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 16 | ||||
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 25 |
6 files changed, 58 insertions, 23 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 0fac2cb1ea18..e474ca2b2bfe 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -450,6 +450,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | |||
450 | dentry = d_lookup(parent, &filename); | 450 | dentry = d_lookup(parent, &filename); |
451 | if (dentry != NULL) { | 451 | if (dentry != NULL) { |
452 | if (nfs_same_file(dentry, entry)) { | 452 | if (nfs_same_file(dentry, entry)) { |
453 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
453 | status = nfs_refresh_inode(dentry->d_inode, entry->fattr); | 454 | status = nfs_refresh_inode(dentry->d_inode, entry->fattr); |
454 | if (!status) | 455 | if (!status) |
455 | nfs_setsecurity(dentry->d_inode, entry->fattr, entry->label); | 456 | nfs_setsecurity(dentry->d_inode, entry->fattr, entry->label); |
@@ -817,7 +818,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) | |||
817 | nfs_readdir_descriptor_t my_desc, | 818 | nfs_readdir_descriptor_t my_desc, |
818 | *desc = &my_desc; | 819 | *desc = &my_desc; |
819 | struct nfs_open_dir_context *dir_ctx = file->private_data; | 820 | struct nfs_open_dir_context *dir_ctx = file->private_data; |
820 | int res; | 821 | int res = 0; |
821 | 822 | ||
822 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 823 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
823 | dentry->d_parent->d_name.name, dentry->d_name.name, | 824 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -839,7 +840,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) | |||
839 | desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; | 840 | desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; |
840 | 841 | ||
841 | nfs_block_sillyrename(dentry); | 842 | nfs_block_sillyrename(dentry); |
842 | res = nfs_revalidate_mapping(inode, file->f_mapping); | 843 | if (ctx->pos == 0 || nfs_attribute_cache_expired(inode)) |
844 | res = nfs_revalidate_mapping(inode, file->f_mapping); | ||
843 | if (res < 0) | 845 | if (res < 0) |
844 | goto out; | 846 | goto out; |
845 | 847 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index c93639e6cf68..af6e806044d7 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -936,7 +936,7 @@ int nfs_attribute_timeout(struct inode *inode) | |||
936 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); | 936 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); |
937 | } | 937 | } |
938 | 938 | ||
939 | static int nfs_attribute_cache_expired(struct inode *inode) | 939 | int nfs_attribute_cache_expired(struct inode *inode) |
940 | { | 940 | { |
941 | if (nfs_have_delegated_attributes(inode)) | 941 | if (nfs_have_delegated_attributes(inode)) |
942 | return 0; | 942 | return 0; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index a2c7c28049d5..f1bdb7254776 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -888,6 +888,28 @@ out: | |||
888 | return PageUptodate(page) != 0; | 888 | return PageUptodate(page) != 0; |
889 | } | 889 | } |
890 | 890 | ||
891 | /* If we know the page is up to date, and we're not using byte range locks (or | ||
892 | * if we have the whole file locked for writing), it may be more efficient to | ||
893 | * extend the write to cover the entire page in order to avoid fragmentation | ||
894 | * inefficiencies. | ||
895 | * | ||
896 | * If the file is opened for synchronous writes or if we have a write delegation | ||
897 | * from the server then we can just skip the rest of the checks. | ||
898 | */ | ||
899 | static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode) | ||
900 | { | ||
901 | if (file->f_flags & O_DSYNC) | ||
902 | return 0; | ||
903 | if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) | ||
904 | return 1; | ||
905 | if (nfs_write_pageuptodate(page, inode) && (inode->i_flock == NULL || | ||
906 | (inode->i_flock->fl_start == 0 && | ||
907 | inode->i_flock->fl_end == OFFSET_MAX && | ||
908 | inode->i_flock->fl_type != F_RDLCK))) | ||
909 | return 1; | ||
910 | return 0; | ||
911 | } | ||
912 | |||
891 | /* | 913 | /* |
892 | * Update and possibly write a cached page of an NFS file. | 914 | * Update and possibly write a cached page of an NFS file. |
893 | * | 915 | * |
@@ -908,14 +930,7 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
908 | file->f_path.dentry->d_name.name, count, | 930 | file->f_path.dentry->d_name.name, count, |
909 | (long long)(page_file_offset(page) + offset)); | 931 | (long long)(page_file_offset(page) + offset)); |
910 | 932 | ||
911 | /* If we're not using byte range locks, and we know the page | 933 | if (nfs_can_extend_write(file, page, inode)) { |
912 | * is up to date, it may be more efficient to extend the write | ||
913 | * to cover the entire page in order to avoid fragmentation | ||
914 | * inefficiencies. | ||
915 | */ | ||
916 | if (nfs_write_pageuptodate(page, inode) && | ||
917 | inode->i_flock == NULL && | ||
918 | !(file->f_flags & O_DSYNC)) { | ||
919 | count = max(count + offset, nfs_page_length(page)); | 934 | count = max(count + offset, nfs_page_length(page)); |
920 | offset = 0; | 935 | offset = 0; |
921 | } | 936 | } |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 0b176297aaf6..7125cef74164 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -348,6 +348,7 @@ extern int nfs_permission(struct inode *, int); | |||
348 | extern int nfs_open(struct inode *, struct file *); | 348 | extern int nfs_open(struct inode *, struct file *); |
349 | extern int nfs_release(struct inode *, struct file *); | 349 | extern int nfs_release(struct inode *, struct file *); |
350 | extern int nfs_attribute_timeout(struct inode *inode); | 350 | extern int nfs_attribute_timeout(struct inode *inode); |
351 | extern int nfs_attribute_cache_expired(struct inode *inode); | ||
351 | extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode); | 352 | extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode); |
352 | extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); | 353 | extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); |
353 | extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); | 354 | extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f0339ae9bf37..aa401560777b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -290,7 +290,7 @@ static int rpc_client_register(const struct rpc_create_args *args, | |||
290 | struct rpc_auth *auth; | 290 | struct rpc_auth *auth; |
291 | struct net *net = rpc_net_ns(clnt); | 291 | struct net *net = rpc_net_ns(clnt); |
292 | struct super_block *pipefs_sb; | 292 | struct super_block *pipefs_sb; |
293 | int err = 0; | 293 | int err; |
294 | 294 | ||
295 | pipefs_sb = rpc_get_sb_net(net); | 295 | pipefs_sb = rpc_get_sb_net(net); |
296 | if (pipefs_sb) { | 296 | if (pipefs_sb) { |
@@ -299,6 +299,10 @@ static int rpc_client_register(const struct rpc_create_args *args, | |||
299 | goto out; | 299 | goto out; |
300 | } | 300 | } |
301 | 301 | ||
302 | rpc_register_client(clnt); | ||
303 | if (pipefs_sb) | ||
304 | rpc_put_sb_net(net); | ||
305 | |||
302 | auth = rpcauth_create(args->authflavor, clnt); | 306 | auth = rpcauth_create(args->authflavor, clnt); |
303 | if (IS_ERR(auth)) { | 307 | if (IS_ERR(auth)) { |
304 | dprintk("RPC: Couldn't create auth handle (flavor %u)\n", | 308 | dprintk("RPC: Couldn't create auth handle (flavor %u)\n", |
@@ -306,16 +310,14 @@ static int rpc_client_register(const struct rpc_create_args *args, | |||
306 | err = PTR_ERR(auth); | 310 | err = PTR_ERR(auth); |
307 | goto err_auth; | 311 | goto err_auth; |
308 | } | 312 | } |
309 | 313 | return 0; | |
310 | rpc_register_client(clnt); | 314 | err_auth: |
315 | pipefs_sb = rpc_get_sb_net(net); | ||
316 | __rpc_clnt_remove_pipedir(clnt); | ||
311 | out: | 317 | out: |
312 | if (pipefs_sb) | 318 | if (pipefs_sb) |
313 | rpc_put_sb_net(net); | 319 | rpc_put_sb_net(net); |
314 | return err; | 320 | return err; |
315 | |||
316 | err_auth: | ||
317 | __rpc_clnt_remove_pipedir(clnt); | ||
318 | goto out; | ||
319 | } | 321 | } |
320 | 322 | ||
321 | static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) | 323 | static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 4679df5a6d50..61239a2cb786 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -480,6 +480,23 @@ static const struct dentry_operations rpc_dentry_operations = { | |||
480 | .d_delete = rpc_delete_dentry, | 480 | .d_delete = rpc_delete_dentry, |
481 | }; | 481 | }; |
482 | 482 | ||
483 | /* | ||
484 | * Lookup the data. This is trivial - if the dentry didn't already | ||
485 | * exist, we know it is negative. | ||
486 | */ | ||
487 | static struct dentry * | ||
488 | rpc_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) | ||
489 | { | ||
490 | if (dentry->d_name.len > NAME_MAX) | ||
491 | return ERR_PTR(-ENAMETOOLONG); | ||
492 | d_add(dentry, NULL); | ||
493 | return NULL; | ||
494 | } | ||
495 | |||
496 | static const struct inode_operations rpc_dir_inode_operations = { | ||
497 | .lookup = rpc_lookup, | ||
498 | }; | ||
499 | |||
483 | static struct inode * | 500 | static struct inode * |
484 | rpc_get_inode(struct super_block *sb, umode_t mode) | 501 | rpc_get_inode(struct super_block *sb, umode_t mode) |
485 | { | 502 | { |
@@ -492,7 +509,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode) | |||
492 | switch (mode & S_IFMT) { | 509 | switch (mode & S_IFMT) { |
493 | case S_IFDIR: | 510 | case S_IFDIR: |
494 | inode->i_fop = &simple_dir_operations; | 511 | inode->i_fop = &simple_dir_operations; |
495 | inode->i_op = &simple_dir_inode_operations; | 512 | inode->i_op = &rpc_dir_inode_operations; |
496 | inc_nlink(inode); | 513 | inc_nlink(inode); |
497 | default: | 514 | default: |
498 | break; | 515 | break; |
@@ -666,11 +683,8 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, | |||
666 | if (!dentry) | 683 | if (!dentry) |
667 | return ERR_PTR(-ENOMEM); | 684 | return ERR_PTR(-ENOMEM); |
668 | } | 685 | } |
669 | if (dentry->d_inode == NULL) { | 686 | if (dentry->d_inode == NULL) |
670 | if (!dentry->d_op) | ||
671 | d_set_d_op(dentry, &rpc_dentry_operations); | ||
672 | return dentry; | 687 | return dentry; |
673 | } | ||
674 | dput(dentry); | 688 | dput(dentry); |
675 | return ERR_PTR(-EEXIST); | 689 | return ERR_PTR(-EEXIST); |
676 | } | 690 | } |
@@ -1117,6 +1131,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) | |||
1117 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 1131 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
1118 | sb->s_magic = RPCAUTH_GSSMAGIC; | 1132 | sb->s_magic = RPCAUTH_GSSMAGIC; |
1119 | sb->s_op = &s_ops; | 1133 | sb->s_op = &s_ops; |
1134 | sb->s_d_op = &rpc_dentry_operations; | ||
1120 | sb->s_time_gran = 1; | 1135 | sb->s_time_gran = 1; |
1121 | 1136 | ||
1122 | inode = rpc_get_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); | 1137 | inode = rpc_get_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); |