diff options
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 4a48fe4b84b6..d9f3d067cd15 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -69,21 +69,28 @@ const struct address_space_operations nfs_dir_aops = { | |||
69 | 69 | ||
70 | static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred) | 70 | static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred) |
71 | { | 71 | { |
72 | struct nfs_inode *nfsi = NFS_I(dir); | ||
72 | struct nfs_open_dir_context *ctx; | 73 | struct nfs_open_dir_context *ctx; |
73 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | 74 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); |
74 | if (ctx != NULL) { | 75 | if (ctx != NULL) { |
75 | ctx->duped = 0; | 76 | ctx->duped = 0; |
76 | ctx->attr_gencount = NFS_I(dir)->attr_gencount; | 77 | ctx->attr_gencount = nfsi->attr_gencount; |
77 | ctx->dir_cookie = 0; | 78 | ctx->dir_cookie = 0; |
78 | ctx->dup_cookie = 0; | 79 | ctx->dup_cookie = 0; |
79 | ctx->cred = get_rpccred(cred); | 80 | ctx->cred = get_rpccred(cred); |
81 | spin_lock(&dir->i_lock); | ||
82 | list_add(&ctx->list, &nfsi->open_files); | ||
83 | spin_unlock(&dir->i_lock); | ||
80 | return ctx; | 84 | return ctx; |
81 | } | 85 | } |
82 | return ERR_PTR(-ENOMEM); | 86 | return ERR_PTR(-ENOMEM); |
83 | } | 87 | } |
84 | 88 | ||
85 | static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) | 89 | static void put_nfs_open_dir_context(struct inode *dir, struct nfs_open_dir_context *ctx) |
86 | { | 90 | { |
91 | spin_lock(&dir->i_lock); | ||
92 | list_del(&ctx->list); | ||
93 | spin_unlock(&dir->i_lock); | ||
87 | put_rpccred(ctx->cred); | 94 | put_rpccred(ctx->cred); |
88 | kfree(ctx); | 95 | kfree(ctx); |
89 | } | 96 | } |
@@ -126,7 +133,7 @@ out: | |||
126 | static int | 133 | static int |
127 | nfs_closedir(struct inode *inode, struct file *filp) | 134 | nfs_closedir(struct inode *inode, struct file *filp) |
128 | { | 135 | { |
129 | put_nfs_open_dir_context(filp->private_data); | 136 | put_nfs_open_dir_context(filp->f_path.dentry->d_inode, filp->private_data); |
130 | return 0; | 137 | return 0; |
131 | } | 138 | } |
132 | 139 | ||
@@ -306,10 +313,9 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des | |||
306 | if (printk_ratelimit()) { | 313 | if (printk_ratelimit()) { |
307 | pr_notice("NFS: directory %pD2 contains a readdir loop." | 314 | pr_notice("NFS: directory %pD2 contains a readdir loop." |
308 | "Please contact your server vendor. " | 315 | "Please contact your server vendor. " |
309 | "The file: %s has duplicate cookie %llu\n", | 316 | "The file: %.*s has duplicate cookie %llu\n", |
310 | desc->file, | 317 | desc->file, array->array[i].string.len, |
311 | array->array[i].string.name, | 318 | array->array[i].string.name, *desc->dir_cookie); |
312 | *desc->dir_cookie); | ||
313 | } | 319 | } |
314 | status = -ELOOP; | 320 | status = -ELOOP; |
315 | goto out; | 321 | goto out; |
@@ -437,6 +443,22 @@ void nfs_advise_use_readdirplus(struct inode *dir) | |||
437 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags); | 443 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags); |
438 | } | 444 | } |
439 | 445 | ||
446 | /* | ||
447 | * This function is mainly for use by nfs_getattr(). | ||
448 | * | ||
449 | * If this is an 'ls -l', we want to force use of readdirplus. | ||
450 | * Do this by checking if there is an active file descriptor | ||
451 | * and calling nfs_advise_use_readdirplus, then forcing a | ||
452 | * cache flush. | ||
453 | */ | ||
454 | void nfs_force_use_readdirplus(struct inode *dir) | ||
455 | { | ||
456 | if (!list_empty(&NFS_I(dir)->open_files)) { | ||
457 | nfs_advise_use_readdirplus(dir); | ||
458 | nfs_zap_mapping(dir, dir->i_mapping); | ||
459 | } | ||
460 | } | ||
461 | |||
440 | static | 462 | static |
441 | void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | 463 | void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) |
442 | { | 464 | { |
@@ -815,6 +837,17 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc) | |||
815 | goto out; | 837 | goto out; |
816 | } | 838 | } |
817 | 839 | ||
840 | static bool nfs_dir_mapping_need_revalidate(struct inode *dir) | ||
841 | { | ||
842 | struct nfs_inode *nfsi = NFS_I(dir); | ||
843 | |||
844 | if (nfs_attribute_cache_expired(dir)) | ||
845 | return true; | ||
846 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) | ||
847 | return true; | ||
848 | return false; | ||
849 | } | ||
850 | |||
818 | /* The file offset position represents the dirent entry number. A | 851 | /* The file offset position represents the dirent entry number. A |
819 | last cookie cache takes care of the common case of reading the | 852 | last cookie cache takes care of the common case of reading the |
820 | whole directory. | 853 | whole directory. |
@@ -847,7 +880,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) | |||
847 | desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; | 880 | desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; |
848 | 881 | ||
849 | nfs_block_sillyrename(dentry); | 882 | nfs_block_sillyrename(dentry); |
850 | if (ctx->pos == 0 || nfs_attribute_cache_expired(inode)) | 883 | if (ctx->pos == 0 || nfs_dir_mapping_need_revalidate(inode)) |
851 | res = nfs_revalidate_mapping(inode, file->f_mapping); | 884 | res = nfs_revalidate_mapping(inode, file->f_mapping); |
852 | if (res < 0) | 885 | if (res < 0) |
853 | goto out; | 886 | goto out; |
@@ -1911,6 +1944,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1911 | struct inode *old_inode = old_dentry->d_inode; | 1944 | struct inode *old_inode = old_dentry->d_inode; |
1912 | struct inode *new_inode = new_dentry->d_inode; | 1945 | struct inode *new_inode = new_dentry->d_inode; |
1913 | struct dentry *dentry = NULL, *rehash = NULL; | 1946 | struct dentry *dentry = NULL, *rehash = NULL; |
1947 | struct rpc_task *task; | ||
1914 | int error = -EBUSY; | 1948 | int error = -EBUSY; |
1915 | 1949 | ||
1916 | dfprintk(VFS, "NFS: rename(%pd2 -> %pd2, ct=%d)\n", | 1950 | dfprintk(VFS, "NFS: rename(%pd2 -> %pd2, ct=%d)\n", |
@@ -1958,8 +1992,16 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1958 | if (new_inode != NULL) | 1992 | if (new_inode != NULL) |
1959 | NFS_PROTO(new_inode)->return_delegation(new_inode); | 1993 | NFS_PROTO(new_inode)->return_delegation(new_inode); |
1960 | 1994 | ||
1961 | error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, | 1995 | task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL); |
1962 | new_dir, &new_dentry->d_name); | 1996 | if (IS_ERR(task)) { |
1997 | error = PTR_ERR(task); | ||
1998 | goto out; | ||
1999 | } | ||
2000 | |||
2001 | error = rpc_wait_for_completion_task(task); | ||
2002 | if (error == 0) | ||
2003 | error = task->tk_status; | ||
2004 | rpc_put_task(task); | ||
1963 | nfs_mark_for_revalidate(old_inode); | 2005 | nfs_mark_for_revalidate(old_inode); |
1964 | out: | 2006 | out: |
1965 | if (rehash) | 2007 | if (rehash) |