aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-14 15:39:58 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-19 15:21:39 -0400
commite4eff1a622edd6ab7b73acd5d8763aa2fa3fee49 (patch)
tree257d6675733d4af122a77054281e1d7d5062d904 /fs/nfs
parent4fdc17b2a7f4d9db5b08e0f963d0027f714e4104 (diff)
SUNRPC: Clean up the sillyrename code
Fix a couple of bugs: - Don't rely on the parent dentry still being valid when the call completes. Fixes a race with shrink_dcache_for_umount_subtree() - Don't remove the file if the filehandle has been labelled as stale. Fix a couple of inefficiencies - Remove the global list of sillyrenamed files. Instead we can cache the sillyrename information in the dentry->d_fsdata - Move common code from unlink_setup/unlink_done into fs/nfs/unlink.c Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c4
-rw-r--r--fs/nfs/nfs3proc.c38
-rw-r--r--fs/nfs/nfs4proc.c50
-rw-r--r--fs/nfs/proc.c26
-rw-r--r--fs/nfs/unlink.c195
5 files changed, 116 insertions, 197 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 0fa1dbcdadb9..ea97408e423e 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -869,7 +869,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
869 if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { 869 if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
870 lock_kernel(); 870 lock_kernel();
871 drop_nlink(inode); 871 drop_nlink(inode);
872 nfs_complete_unlink(dentry); 872 nfs_complete_unlink(dentry, inode);
873 unlock_kernel(); 873 unlock_kernel();
874 } 874 }
875 /* When creating a negative dentry, we want to renew d_time */ 875 /* When creating a negative dentry, we want to renew d_time */
@@ -1411,7 +1411,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
1411 nfs_renew_times(dentry); 1411 nfs_renew_times(dentry);
1412 nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 1412 nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1413 d_move(dentry, sdentry); 1413 d_move(dentry, sdentry);
1414 error = nfs_async_unlink(dentry); 1414 error = nfs_async_unlink(dir, dentry);
1415 /* If we return 0 we don't unlink */ 1415 /* If we return 0 we don't unlink */
1416 } 1416 }
1417 dput(sdentry); 1417 dput(sdentry);
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index eac07f2c99dd..c7ca5d70870b 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -370,41 +370,21 @@ nfs3_proc_remove(struct inode *dir, struct qstr *name)
370 return status; 370 return status;
371} 371}
372 372
373static int 373static void
374nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) 374nfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
375{ 375{
376 struct unlinkxdr {
377 struct nfs_removeargs arg;
378 struct nfs_removeres res;
379 } *ptr;
380
381 ptr = kmalloc(sizeof(*ptr), GFP_KERNEL);
382 if (!ptr)
383 return -ENOMEM;
384 ptr->arg.fh = NFS_FH(dir->d_inode);
385 ptr->arg.name.name = name->name;
386 ptr->arg.name.len = name->len;
387 nfs_fattr_init(&ptr->res.dir_attr);
388 msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE]; 376 msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
389 msg->rpc_argp = &ptr->arg;
390 msg->rpc_resp = &ptr->res;
391 return 0;
392} 377}
393 378
394static int 379static int
395nfs3_proc_unlink_done(struct dentry *dir, struct rpc_task *task) 380nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
396{ 381{
397 struct rpc_message *msg = &task->tk_msg; 382 struct nfs_removeres *res;
398 struct nfs_fattr *dir_attr; 383 if (nfs3_async_handle_jukebox(task, dir))
399 384 return 0;
400 if (nfs3_async_handle_jukebox(task, dir->d_inode)) 385 res = task->tk_msg.rpc_resp;
401 return 1; 386 nfs_post_op_update_inode(dir, &res->dir_attr);
402 if (msg->rpc_argp) { 387 return 1;
403 dir_attr = &((struct nfs_removeres*)msg->rpc_resp)->dir_attr;
404 nfs_post_op_update_inode(dir->d_inode, dir_attr);
405 kfree(msg->rpc_argp);
406 }
407 return 0;
408} 388}
409 389
410static int 390static int
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 23dc25dbc6fa..6ca2795ccd9c 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1962,48 +1962,26 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
1962 return err; 1962 return err;
1963} 1963}
1964 1964
1965struct unlink_desc { 1965static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
1966 struct nfs_removeargs args;
1967 struct nfs_removeres res;
1968};
1969
1970static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir,
1971 struct qstr *name)
1972{ 1966{
1973 struct nfs_server *server = NFS_SERVER(dir->d_inode); 1967 struct nfs_server *server = NFS_SERVER(dir);
1974 struct unlink_desc *up; 1968 struct nfs_removeargs *args = msg->rpc_argp;
1969 struct nfs_removeres *res = msg->rpc_resp;
1975 1970
1976 up = kmalloc(sizeof(*up), GFP_KERNEL); 1971 args->bitmask = server->attr_bitmask;
1977 if (!up) 1972 res->server = server;
1978 return -ENOMEM;
1979
1980 up->args.fh = NFS_FH(dir->d_inode);
1981 up->args.name.len = name->len;
1982 up->args.name.name = name->name;
1983 up->args.bitmask = server->attr_bitmask;
1984 up->res.server = server;
1985 nfs_fattr_init(&up->res.dir_attr);
1986
1987 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; 1973 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
1988 msg->rpc_argp = &up->args;
1989 msg->rpc_resp = &up->res;
1990 return 0;
1991} 1974}
1992 1975
1993static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) 1976static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
1994{ 1977{
1995 struct rpc_message *msg = &task->tk_msg; 1978 struct nfs_removeres *res = task->tk_msg.rpc_resp;
1996 struct unlink_desc *up; 1979
1997 1980 if (nfs4_async_handle_error(task, res->server) == -EAGAIN)
1998 if (msg->rpc_resp != NULL) { 1981 return 0;
1999 up = container_of(msg->rpc_resp, struct unlink_desc, res); 1982 update_changeattr(dir, &res->cinfo);
2000 update_changeattr(dir->d_inode, &up->res.cinfo); 1983 nfs_post_op_update_inode(dir, &res->dir_attr);
2001 nfs_post_op_update_inode(dir->d_inode, &up->res.dir_attr); 1984 return 1;
2002 kfree(up);
2003 msg->rpc_resp = NULL;
2004 msg->rpc_argp = NULL;
2005 }
2006 return 0;
2007} 1985}
2008 1986
2009static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, 1987static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 3b3eb692e0f4..845cdde1d8b7 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -291,32 +291,16 @@ nfs_proc_remove(struct inode *dir, struct qstr *name)
291 return status; 291 return status;
292} 292}
293 293
294static int 294static void
295nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) 295nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
296{ 296{
297 struct nfs_removeargs *arg;
298
299 arg = kmalloc(sizeof(*arg), GFP_KERNEL);
300 if (!arg)
301 return -ENOMEM;
302 arg->fh = NFS_FH(dir->d_inode);
303 arg->name.name = name->name;
304 arg->name.len = name->len;
305 msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE]; 297 msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE];
306 msg->rpc_argp = arg;
307 return 0;
308} 298}
309 299
310static int 300static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
311nfs_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
312{ 301{
313 struct rpc_message *msg = &task->tk_msg; 302 nfs_mark_for_revalidate(dir);
314 303 return 1;
315 if (msg->rpc_argp) {
316 nfs_mark_for_revalidate(dir->d_inode);
317 kfree(msg->rpc_argp);
318 }
319 return 0;
320} 304}
321 305
322static int 306static int
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index 0e28189c2151..045ab805c17f 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -3,7 +3,6 @@
3 * 3 *
4 * nfs sillydelete handling 4 * nfs sillydelete handling
5 * 5 *
6 * NOTE: we rely on holding the BKL for list manipulation protection.
7 */ 6 */
8 7
9#include <linux/slab.h> 8#include <linux/slab.h>
@@ -15,46 +14,23 @@
15 14
16 15
17struct nfs_unlinkdata { 16struct nfs_unlinkdata {
18 struct nfs_unlinkdata *next; 17 struct nfs_removeargs args;
19 struct dentry *dir, *dentry; 18 struct nfs_removeres res;
20 struct qstr name; 19 struct inode *dir;
21 struct rpc_task task;
22 struct rpc_cred *cred; 20 struct rpc_cred *cred;
23 unsigned int count;
24}; 21};
25 22
26static struct nfs_unlinkdata *nfs_deletes;
27static RPC_WAITQ(nfs_delete_queue, "nfs_delete_queue");
28
29/**
30 * nfs_detach_unlinkdata - Remove asynchronous unlink from global list
31 * @data: pointer to descriptor
32 */
33static inline void
34nfs_detach_unlinkdata(struct nfs_unlinkdata *data)
35{
36 struct nfs_unlinkdata **q;
37
38 for (q = &nfs_deletes; *q != NULL; q = &((*q)->next)) {
39 if (*q == data) {
40 *q = data->next;
41 break;
42 }
43 }
44}
45
46/** 23/**
47 * nfs_put_unlinkdata - release data from a sillydelete operation. 24 * nfs_free_unlinkdata - release data from a sillydelete operation.
48 * @data: pointer to unlink structure. 25 * @data: pointer to unlink structure.
49 */ 26 */
50static void 27static void
51nfs_put_unlinkdata(struct nfs_unlinkdata *data) 28nfs_free_unlinkdata(struct nfs_unlinkdata *data)
52{ 29{
53 if (--data->count == 0) { 30 iput(data->dir);
54 nfs_detach_unlinkdata(data); 31 put_rpccred(data->cred);
55 kfree(data->name.name); 32 kfree(data->args.name.name);
56 kfree(data); 33 kfree(data);
57 }
58} 34}
59 35
60#define NAME_ALLOC_LEN(len) ((len+16) & ~15) 36#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
@@ -63,50 +39,36 @@ nfs_put_unlinkdata(struct nfs_unlinkdata *data)
63 * @dentry: pointer to dentry 39 * @dentry: pointer to dentry
64 * @data: nfs_unlinkdata 40 * @data: nfs_unlinkdata
65 */ 41 */
66static inline void 42static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
67nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
68{ 43{
69 char *str; 44 char *str;
70 int len = dentry->d_name.len; 45 int len = dentry->d_name.len;
71 46
72 str = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL); 47 str = kmemdup(dentry->d_name.name, NAME_ALLOC_LEN(len), GFP_KERNEL);
73 if (!str) 48 if (!str)
74 return; 49 return -ENOMEM;
75 memcpy(str, dentry->d_name.name, len); 50 data->args.name.len = len;
76 if (!data->name.len) { 51 data->args.name.name = str;
77 data->name.len = len; 52 return 0;
78 data->name.name = str;
79 } else
80 kfree(str);
81} 53}
82 54
83/** 55/**
84 * nfs_async_unlink_init - Initialize the RPC info 56 * nfs_async_unlink_init - Initialize the RPC info
85 * @task: rpc_task of the sillydelete 57 * task: rpc_task of the sillydelete
86 *
87 * We delay initializing RPC info until after the call to dentry_iput()
88 * in order to minimize races against rename().
89 */ 58 */
90static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) 59static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
91{ 60{
92 struct nfs_unlinkdata *data = calldata; 61 struct nfs_unlinkdata *data = calldata;
93 struct dentry *dir = data->dir; 62 struct inode *dir = data->dir;
94 struct rpc_message msg = { 63 struct rpc_message msg = {
95 .rpc_cred = data->cred, 64 .rpc_argp = &data->args,
65 .rpc_resp = &data->res,
66 .rpc_cred = data->cred,
96 }; 67 };
97 int status = -ENOENT;
98
99 if (!data->name.len)
100 goto out_err;
101 68
102 status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name); 69 nfs_begin_data_update(dir);
103 if (status < 0) 70 NFS_PROTO(dir)->unlink_setup(&msg, dir);
104 goto out_err;
105 nfs_begin_data_update(dir->d_inode);
106 rpc_call_setup(task, &msg, 0); 71 rpc_call_setup(task, &msg, 0);
107 return;
108 out_err:
109 rpc_exit(task, status);
110} 72}
111 73
112/** 74/**
@@ -117,19 +79,13 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
117 */ 79 */
118static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) 80static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
119{ 81{
120 struct nfs_unlinkdata *data = calldata; 82 struct nfs_unlinkdata *data = calldata;
121 struct dentry *dir = data->dir; 83 struct inode *dir = data->dir;
122 struct inode *dir_i; 84
123 85 if (!NFS_PROTO(dir)->unlink_done(task, dir))
124 if (!dir) 86 rpc_restart_call(task);
125 return; 87 else
126 dir_i = dir->d_inode; 88 nfs_end_data_update(dir);
127 nfs_end_data_update(dir_i);
128 if (NFS_PROTO(dir_i)->unlink_done(dir, task))
129 return;
130 put_rpccred(data->cred);
131 data->cred = NULL;
132 dput(dir);
133} 89}
134 90
135/** 91/**
@@ -142,7 +98,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
142static void nfs_async_unlink_release(void *calldata) 98static void nfs_async_unlink_release(void *calldata)
143{ 99{
144 struct nfs_unlinkdata *data = calldata; 100 struct nfs_unlinkdata *data = calldata;
145 nfs_put_unlinkdata(data); 101 nfs_free_unlinkdata(data);
146} 102}
147 103
148static const struct rpc_call_ops nfs_unlink_ops = { 104static const struct rpc_call_ops nfs_unlink_ops = {
@@ -151,73 +107,94 @@ static const struct rpc_call_ops nfs_unlink_ops = {
151 .rpc_release = nfs_async_unlink_release, 107 .rpc_release = nfs_async_unlink_release,
152}; 108};
153 109
110static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
111{
112 struct rpc_task *task;
113 struct dentry *parent;
114 struct inode *dir;
115
116 if (nfs_copy_dname(dentry, data) < 0)
117 goto out_free;
118
119 parent = dget_parent(dentry);
120 if (parent == NULL)
121 goto out_free;
122 dir = igrab(parent->d_inode);
123 dput(parent);
124 if (dir == NULL)
125 goto out_free;
126
127 data->dir = dir;
128 data->args.fh = NFS_FH(dir);
129 nfs_fattr_init(&data->res.dir_attr);
130
131 task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data);
132 if (!IS_ERR(task))
133 rpc_put_task(task);
134 return 1;
135out_free:
136 return 0;
137}
138
154/** 139/**
155 * nfs_async_unlink - asynchronous unlinking of a file 140 * nfs_async_unlink - asynchronous unlinking of a file
141 * @dir: parent directory of dentry
156 * @dentry: dentry to unlink 142 * @dentry: dentry to unlink
157 */ 143 */
158int 144int
159nfs_async_unlink(struct dentry *dentry) 145nfs_async_unlink(struct inode *dir, struct dentry *dentry)
160{ 146{
161 struct dentry *dir = dentry->d_parent; 147 struct nfs_unlinkdata *data;
162 struct nfs_unlinkdata *data; 148 int status = -ENOMEM;
163 struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode);
164 int status = -ENOMEM;
165 149
166 data = kzalloc(sizeof(*data), GFP_KERNEL); 150 data = kzalloc(sizeof(*data), GFP_KERNEL);
167 if (!data) 151 if (data == NULL)
168 goto out; 152 goto out;
169 153
170 data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); 154 data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
171 if (IS_ERR(data->cred)) { 155 if (IS_ERR(data->cred)) {
172 status = PTR_ERR(data->cred); 156 status = PTR_ERR(data->cred);
173 goto out_free; 157 goto out_free;
174 } 158 }
175 data->dir = dget(dir);
176 data->dentry = dentry;
177
178 data->next = nfs_deletes;
179 nfs_deletes = data;
180 data->count = 1;
181
182 rpc_init_task(&data->task, clnt, RPC_TASK_ASYNC, &nfs_unlink_ops, data);
183 159
160 status = -EBUSY;
184 spin_lock(&dentry->d_lock); 161 spin_lock(&dentry->d_lock);
162 if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
163 goto out_unlock;
185 dentry->d_flags |= DCACHE_NFSFS_RENAMED; 164 dentry->d_flags |= DCACHE_NFSFS_RENAMED;
165 dentry->d_fsdata = data;
186 spin_unlock(&dentry->d_lock); 166 spin_unlock(&dentry->d_lock);
187 167 return 0;
188 rpc_sleep_on(&nfs_delete_queue, &data->task, NULL, NULL); 168out_unlock:
189 status = 0; 169 spin_unlock(&dentry->d_lock);
190 out: 170 put_rpccred(data->cred);
191 return status;
192out_free: 171out_free:
193 kfree(data); 172 kfree(data);
173out:
194 return status; 174 return status;
195} 175}
196 176
197/** 177/**
198 * nfs_complete_unlink - Initialize completion of the sillydelete 178 * nfs_complete_unlink - Initialize completion of the sillydelete
199 * @dentry: dentry to delete 179 * @dentry: dentry to delete
180 * @inode: inode
200 * 181 *
201 * Since we're most likely to be called by dentry_iput(), we 182 * Since we're most likely to be called by dentry_iput(), we
202 * only use the dentry to find the sillydelete. We then copy the name 183 * only use the dentry to find the sillydelete. We then copy the name
203 * into the qstr. 184 * into the qstr.
204 */ 185 */
205void 186void
206nfs_complete_unlink(struct dentry *dentry) 187nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
207{ 188{
208 struct nfs_unlinkdata *data; 189 struct nfs_unlinkdata *data = NULL;
209 190
210 for(data = nfs_deletes; data != NULL; data = data->next) {
211 if (dentry == data->dentry)
212 break;
213 }
214 if (!data)
215 return;
216 data->count++;
217 nfs_copy_dname(dentry, data);
218 spin_lock(&dentry->d_lock); 191 spin_lock(&dentry->d_lock);
219 dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; 192 if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
193 dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
194 data = dentry->d_fsdata;
195 }
220 spin_unlock(&dentry->d_lock); 196 spin_unlock(&dentry->d_lock);
221 rpc_wake_up_task(&data->task); 197
222 nfs_put_unlinkdata(data); 198 if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
199 nfs_free_unlinkdata(data);
223} 200}