Blame view

fs/nfs/unlink.c 15.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   *  linux/fs/nfs/unlink.c
   *
   * nfs sillydelete handling
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
   */
  
  #include <linux/slab.h>
  #include <linux/string.h>
  #include <linux/dcache.h>
  #include <linux/sunrpc/sched.h>
  #include <linux/sunrpc/clnt.h>
  #include <linux/nfs_fs.h>
b35e70411   Linus Torvalds   Avoid compile err...
14
15
  #include <linux/sched.h>
  #include <linux/wait.h>
779c51795   Jeff Layton   nfs: move nfs_sil...
16
  #include <linux/namei.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17

ef818a28f   Steve Dickson   NFS: Stop sillyna...
18
  #include "internal.h"
472cfbd9b   Andy Adamson   nfs41: unlink seq...
19
  #include "nfs4_fs.h"
779c51795   Jeff Layton   nfs: move nfs_sil...
20
21
  #include "iostat.h"
  #include "delegation.h"
ef818a28f   Steve Dickson   NFS: Stop sillyna...
22

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  struct nfs_unlinkdata {
565277f63   Trond Myklebust   NFS: Fix a race i...
24
  	struct hlist_node list;
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
25
26
27
  	struct nfs_removeargs args;
  	struct nfs_removeres res;
  	struct inode *dir;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  	struct rpc_cred	*cred;
d346890be   Trond Myklebust   NFS: Reduce stack...
29
  	struct nfs_fattr dir_attr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  /**
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
32
   * nfs_free_unlinkdata - release data from a sillydelete operation.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
   * @data: pointer to unlink structure.
   */
  static void
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
36
  nfs_free_unlinkdata(struct nfs_unlinkdata *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
38
39
40
41
  	iput(data->dir);
  	put_rpccred(data->cred);
  	kfree(data->args.name.name);
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
  }
  
  #define NAME_ALLOC_LEN(len)	((len+16) & ~15)
  /**
   * nfs_copy_dname - copy dentry name to data structure
   * @dentry: pointer to dentry
   * @data: nfs_unlinkdata
   */
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
50
  static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
  {
  	char		*str;
  	int		len = dentry->d_name.len;
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
54
  	str = kmemdup(dentry->d_name.name, NAME_ALLOC_LEN(len), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  	if (!str)
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
56
57
58
59
  		return -ENOMEM;
  	data->args.name.len = len;
  	data->args.name.name = str;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  }
565277f63   Trond Myklebust   NFS: Fix a race i...
61
62
63
64
65
66
67
68
69
70
71
72
73
  static void nfs_free_dname(struct nfs_unlinkdata *data)
  {
  	kfree(data->args.name.name);
  	data->args.name.name = NULL;
  	data->args.name.len = 0;
  }
  
  static void nfs_dec_sillycount(struct inode *dir)
  {
  	struct nfs_inode *nfsi = NFS_I(dir);
  	if (atomic_dec_return(&nfsi->silly_count) == 1)
  		wake_up(&nfsi->waitqueue);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
   * nfs_async_unlink_done - Sillydelete post-processing
   * @task: rpc_task of the sillydelete
   *
   * Do the directory attribute update.
   */
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
80
  static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
82
83
84
85
  	struct nfs_unlinkdata *data = calldata;
  	struct inode *dir = data->dir;
  
  	if (!NFS_PROTO(dir)->unlink_done(task, dir))
d00c5d438   Trond Myklebust   NFS: Get rid of n...
86
  		rpc_restart_call_prepare(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
92
93
94
95
  }
  
  /**
   * nfs_async_unlink_release - Release the sillydelete data.
   * @task: rpc_task of the sillydelete
   *
   * We need to call nfs_put_unlinkdata as a 'tk_release' task since the
   * rpc_task would be freed too.
   */
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
96
  static void nfs_async_unlink_release(void *calldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
98
  	struct nfs_unlinkdata	*data = calldata;
744d18dbf   Trond Myklebust   NFS: Ensure we ca...
99
  	struct super_block *sb = data->dir->i_sb;
565277f63   Trond Myklebust   NFS: Fix a race i...
100
101
  
  	nfs_dec_sillycount(data->dir);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
102
  	nfs_free_unlinkdata(data);
1daef0a86   Trond Myklebust   NFS: Clean up nfs...
103
  	nfs_sb_deactive(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  }
472cfbd9b   Andy Adamson   nfs41: unlink seq...
105
106
107
108
109
  #if defined(CONFIG_NFS_V4_1)
  void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
  {
  	struct nfs_unlinkdata *data = calldata;
  	struct nfs_server *server = NFS_SERVER(data->dir);
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
110
  	if (nfs4_setup_sequence(server, &data->args.seq_args,
472cfbd9b   Andy Adamson   nfs41: unlink seq...
111
112
113
114
115
  				&data->res.seq_res, 1, task))
  		return;
  	rpc_call_start(task);
  }
  #endif /* CONFIG_NFS_V4_1 */
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
116
117
118
  static const struct rpc_call_ops nfs_unlink_ops = {
  	.rpc_call_done = nfs_async_unlink_done,
  	.rpc_release = nfs_async_unlink_release,
472cfbd9b   Andy Adamson   nfs41: unlink seq...
119
120
121
  #if defined(CONFIG_NFS_V4_1)
  	.rpc_call_prepare = nfs_unlink_prepare,
  #endif /* CONFIG_NFS_V4_1 */
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
122
  };
565277f63   Trond Myklebust   NFS: Fix a race i...
123
  static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data)
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
124
  {
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
125
126
127
128
129
  	struct rpc_message msg = {
  		.rpc_argp = &data->args,
  		.rpc_resp = &data->res,
  		.rpc_cred = data->cred,
  	};
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
130
  	struct rpc_task_setup task_setup_data = {
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
131
  		.rpc_message = &msg,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
132
133
  		.callback_ops = &nfs_unlink_ops,
  		.callback_data = data,
1daef0a86   Trond Myklebust   NFS: Clean up nfs...
134
  		.workqueue = nfsiod_workqueue,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
135
136
  		.flags = RPC_TASK_ASYNC,
  	};
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
137
  	struct rpc_task *task;
565277f63   Trond Myklebust   NFS: Fix a race i...
138
139
140
141
  	struct dentry *alias;
  
  	alias = d_lookup(parent, &data->args.name);
  	if (alias != NULL) {
73ca1001e   Jeff Layton   nfs: don't use d_...
142
  		int ret;
b1942c5f8   Al Viro   nfs: store devnam...
143
  		void *devname_garbage = NULL;
609005c31   Trond Myklebust   NFS: Sillyrename:...
144

565277f63   Trond Myklebust   NFS: Fix a race i...
145
146
147
148
149
  		/*
  		 * Hey, we raced with lookup... See if we need to transfer
  		 * the sillyrename information to the aliased dentry.
  		 */
  		nfs_free_dname(data);
73ca1001e   Jeff Layton   nfs: don't use d_...
150
  		ret = nfs_copy_dname(alias, data);
565277f63   Trond Myklebust   NFS: Fix a race i...
151
  		spin_lock(&alias->d_lock);
73ca1001e   Jeff Layton   nfs: don't use d_...
152
  		if (ret == 0 && alias->d_inode != NULL &&
609005c31   Trond Myklebust   NFS: Sillyrename:...
153
  		    !(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
b1942c5f8   Al Viro   nfs: store devnam...
154
  			devname_garbage = alias->d_fsdata;
565277f63   Trond Myklebust   NFS: Fix a race i...
155
  			alias->d_fsdata = data;
fccca7fc6   Trond Myklebust   NFS: Fix a sillyr...
156
  			alias->d_flags |= DCACHE_NFSFS_RENAMED;
565277f63   Trond Myklebust   NFS: Fix a race i...
157
  			ret = 1;
73ca1001e   Jeff Layton   nfs: don't use d_...
158
159
  		} else
  			ret = 0;
565277f63   Trond Myklebust   NFS: Fix a race i...
160
161
162
  		spin_unlock(&alias->d_lock);
  		nfs_dec_sillycount(dir);
  		dput(alias);
b1942c5f8   Al Viro   nfs: store devnam...
163
164
165
166
167
  		/*
  		 * If we'd displaced old cached devname, free it.  At that
  		 * point dentry is definitely not a root, so we won't need
  		 * that anymore.
  		 */
73ca1001e   Jeff Layton   nfs: don't use d_...
168
  		kfree(devname_garbage);
565277f63   Trond Myklebust   NFS: Fix a race i...
169
170
171
172
173
174
175
  		return ret;
  	}
  	data->dir = igrab(dir);
  	if (!data->dir) {
  		nfs_dec_sillycount(dir);
  		return 0;
  	}
1daef0a86   Trond Myklebust   NFS: Clean up nfs...
176
  	nfs_sb_active(dir->i_sb);
565277f63   Trond Myklebust   NFS: Fix a race i...
177
  	data->args.fh = NFS_FH(dir);
d346890be   Trond Myklebust   NFS: Reduce stack...
178
  	nfs_fattr_init(data->res.dir_attr);
565277f63   Trond Myklebust   NFS: Fix a race i...
179

5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
180
  	NFS_PROTO(dir)->unlink_setup(&msg, dir);
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
181

5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
182
  	task_setup_data.rpc_client = NFS_CLIENT(dir);
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
183
  	task = rpc_run_task(&task_setup_data);
565277f63   Trond Myklebust   NFS: Fix a race i...
184
  	if (!IS_ERR(task))
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
185
  		rpc_put_task_async(task);
565277f63   Trond Myklebust   NFS: Fix a race i...
186
187
188
189
190
  	return 1;
  }
  
  static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
191
192
  	struct dentry *parent;
  	struct inode *dir;
565277f63   Trond Myklebust   NFS: Fix a race i...
193
  	int ret = 0;
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
194

e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
195
196
197
198
  
  	parent = dget_parent(dentry);
  	if (parent == NULL)
  		goto out_free;
565277f63   Trond Myklebust   NFS: Fix a race i...
199
  	dir = parent->d_inode;
565277f63   Trond Myklebust   NFS: Fix a race i...
200
201
202
203
204
205
206
207
208
209
210
211
  	/* Non-exclusive lock protects against concurrent lookup() calls */
  	spin_lock(&dir->i_lock);
  	if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) == 0) {
  		/* Deferred delete */
  		hlist_add_head(&data->list, &NFS_I(dir)->silly_list);
  		spin_unlock(&dir->i_lock);
  		ret = 1;
  		goto out_dput;
  	}
  	spin_unlock(&dir->i_lock);
  	ret = nfs_do_call_unlink(parent, dir, data);
  out_dput:
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
212
  	dput(parent);
565277f63   Trond Myklebust   NFS: Fix a race i...
213
214
215
  out_free:
  	return ret;
  }
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
216

565277f63   Trond Myklebust   NFS: Fix a race i...
217
218
219
  void nfs_block_sillyrename(struct dentry *dentry)
  {
  	struct nfs_inode *nfsi = NFS_I(dentry->d_inode);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
220

565277f63   Trond Myklebust   NFS: Fix a race i...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  	wait_event(nfsi->waitqueue, atomic_cmpxchg(&nfsi->silly_count, 1, 0) == 1);
  }
  
  void nfs_unblock_sillyrename(struct dentry *dentry)
  {
  	struct inode *dir = dentry->d_inode;
  	struct nfs_inode *nfsi = NFS_I(dir);
  	struct nfs_unlinkdata *data;
  
  	atomic_inc(&nfsi->silly_count);
  	spin_lock(&dir->i_lock);
  	while (!hlist_empty(&nfsi->silly_list)) {
  		if (!atomic_inc_not_zero(&nfsi->silly_count))
  			break;
  		data = hlist_entry(nfsi->silly_list.first, struct nfs_unlinkdata, list);
  		hlist_del(&data->list);
  		spin_unlock(&dir->i_lock);
  		if (nfs_do_call_unlink(dentry, dir, data) == 0)
  			nfs_free_unlinkdata(data);
  		spin_lock(&dir->i_lock);
  	}
  	spin_unlock(&dir->i_lock);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
243
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
  /**
   * nfs_async_unlink - asynchronous unlinking of a file
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
246
   * @dir: parent directory of dentry
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
   * @dentry: dentry to unlink
   */
779c51795   Jeff Layton   nfs: move nfs_sil...
249
  static int
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
250
  nfs_async_unlink(struct inode *dir, struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
252
253
  	struct nfs_unlinkdata *data;
  	int status = -ENOMEM;
b1942c5f8   Al Viro   nfs: store devnam...
254
  	void *devname_garbage = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255

bd6475454   Eric Sesterhenn   NFS: kzalloc conv...
256
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
257
  	if (data == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259

98a8e3239   Trond Myklebust   SUNRPC: Add a hel...
260
  	data->cred = rpc_lookup_cred();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
  	if (IS_ERR(data->cred)) {
  		status = PTR_ERR(data->cred);
  		goto out_free;
  	}
d346890be   Trond Myklebust   NFS: Reduce stack...
265
  	data->res.dir_attr = &data->dir_attr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266

e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
267
  	status = -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  	spin_lock(&dentry->d_lock);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
269
270
  	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
b1942c5f8   Al Viro   nfs: store devnam...
272
  	devname_garbage = dentry->d_fsdata;
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
273
  	dentry->d_fsdata = data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  	spin_unlock(&dentry->d_lock);
b1942c5f8   Al Viro   nfs: store devnam...
275
276
277
278
279
280
281
  	/*
  	 * If we'd displaced old cached devname, free it.  At that
  	 * point dentry is definitely not a root, so we won't need
  	 * that anymore.
  	 */
  	if (devname_garbage)
  		kfree(devname_garbage);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
282
283
284
285
  	return 0;
  out_unlock:
  	spin_unlock(&dentry->d_lock);
  	put_rpccred(data->cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
  out_free:
  	kfree(data);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
288
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
  	return status;
  }
  
  /**
   * nfs_complete_unlink - Initialize completion of the sillydelete
   * @dentry: dentry to delete
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
295
   * @inode: inode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
301
   *
   * Since we're most likely to be called by dentry_iput(), we
   * only use the dentry to find the sillydelete. We then copy the name
   * into the qstr.
   */
  void
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
302
  nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
304
  	struct nfs_unlinkdata	*data = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  	spin_lock(&dentry->d_lock);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
307
308
309
  	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
  		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
  		data = dentry->d_fsdata;
b1942c5f8   Al Viro   nfs: store devnam...
310
  		dentry->d_fsdata = NULL;
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
311
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  	spin_unlock(&dentry->d_lock);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
313
314
315
  
  	if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
  		nfs_free_unlinkdata(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
  }
779c51795   Jeff Layton   nfs: move nfs_sil...
317

d3d4152a5   Jeff Layton   nfs: make sillyre...
318
319
320
321
322
323
324
325
326
  /* Cancel a queued async unlink. Called when a sillyrename run fails. */
  static void
  nfs_cancel_async_unlink(struct dentry *dentry)
  {
  	spin_lock(&dentry->d_lock);
  	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
  		struct nfs_unlinkdata *data = dentry->d_fsdata;
  
  		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
b1942c5f8   Al Viro   nfs: store devnam...
327
  		dentry->d_fsdata = NULL;
d3d4152a5   Jeff Layton   nfs: make sillyre...
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
  		spin_unlock(&dentry->d_lock);
  		nfs_free_unlinkdata(data);
  		return;
  	}
  	spin_unlock(&dentry->d_lock);
  }
  
  struct nfs_renamedata {
  	struct nfs_renameargs	args;
  	struct nfs_renameres	res;
  	struct rpc_cred		*cred;
  	struct inode		*old_dir;
  	struct dentry		*old_dentry;
  	struct nfs_fattr	old_fattr;
  	struct inode		*new_dir;
  	struct dentry		*new_dentry;
  	struct nfs_fattr	new_fattr;
  };
  
  /**
   * nfs_async_rename_done - Sillyrename post-processing
   * @task: rpc_task of the sillyrename
   * @calldata: nfs_renamedata for the sillyrename
   *
   * Do the directory attribute updates and the d_move
   */
  static void nfs_async_rename_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs_renamedata *data = calldata;
  	struct inode *old_dir = data->old_dir;
  	struct inode *new_dir = data->new_dir;
73ca1001e   Jeff Layton   nfs: don't use d_...
359
360
  	struct dentry *old_dentry = data->old_dentry;
  	struct dentry *new_dentry = data->new_dentry;
d3d4152a5   Jeff Layton   nfs: make sillyre...
361
362
  
  	if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) {
d00c5d438   Trond Myklebust   NFS: Get rid of n...
363
  		rpc_restart_call_prepare(task);
d3d4152a5   Jeff Layton   nfs: make sillyre...
364
365
366
367
  		return;
  	}
  
  	if (task->tk_status != 0) {
73ca1001e   Jeff Layton   nfs: don't use d_...
368
  		nfs_cancel_async_unlink(old_dentry);
d3d4152a5   Jeff Layton   nfs: make sillyre...
369
370
  		return;
  	}
73ca1001e   Jeff Layton   nfs: don't use d_...
371
372
  	d_drop(old_dentry);
  	d_drop(new_dentry);
d3d4152a5   Jeff Layton   nfs: make sillyre...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  }
  
  /**
   * nfs_async_rename_release - Release the sillyrename data.
   * @calldata: the struct nfs_renamedata to be released
   */
  static void nfs_async_rename_release(void *calldata)
  {
  	struct nfs_renamedata	*data = calldata;
  	struct super_block *sb = data->old_dir->i_sb;
  
  	if (data->old_dentry->d_inode)
  		nfs_mark_for_revalidate(data->old_dentry->d_inode);
  
  	dput(data->old_dentry);
  	dput(data->new_dentry);
  	iput(data->old_dir);
  	iput(data->new_dir);
  	nfs_sb_deactive(sb);
  	put_rpccred(data->cred);
  	kfree(data);
  }
  
  #if defined(CONFIG_NFS_V4_1)
  static void nfs_rename_prepare(struct rpc_task *task, void *calldata)
  {
  	struct nfs_renamedata *data = calldata;
  	struct nfs_server *server = NFS_SERVER(data->old_dir);
  
  	if (nfs4_setup_sequence(server, &data->args.seq_args,
  				&data->res.seq_res, 1, task))
  		return;
  	rpc_call_start(task);
  }
  #endif /* CONFIG_NFS_V4_1 */
  
  static const struct rpc_call_ops nfs_rename_ops = {
  	.rpc_call_done = nfs_async_rename_done,
  	.rpc_release = nfs_async_rename_release,
  #if defined(CONFIG_NFS_V4_1)
  	.rpc_call_prepare = nfs_rename_prepare,
  #endif /* CONFIG_NFS_V4_1 */
  };
  
  /**
   * nfs_async_rename - perform an asynchronous rename operation
   * @old_dir: directory that currently holds the dentry to be renamed
   * @new_dir: target directory for the rename
   * @old_dentry: original dentry to be renamed
   * @new_dentry: dentry to which the old_dentry should be renamed
   *
   * It's expected that valid references to the dentries and inodes are held
   */
  static struct rpc_task *
  nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
  		 struct dentry *old_dentry, struct dentry *new_dentry)
  {
  	struct nfs_renamedata *data;
  	struct rpc_message msg = { };
  	struct rpc_task_setup task_setup_data = {
  		.rpc_message = &msg,
  		.callback_ops = &nfs_rename_ops,
  		.workqueue = nfsiod_workqueue,
  		.rpc_client = NFS_CLIENT(old_dir),
  		.flags = RPC_TASK_ASYNC,
  	};
d3d4152a5   Jeff Layton   nfs: make sillyre...
439

dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
440
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
d3d4152a5   Jeff Layton   nfs: make sillyre...
441
442
  	if (data == NULL)
  		return ERR_PTR(-ENOMEM);
1174dd1f8   Trond Myklebust   NFSv4: Convert a ...
443
  	task_setup_data.callback_data = data;
d3d4152a5   Jeff Layton   nfs: make sillyre...
444
445
446
  
  	data->cred = rpc_lookup_cred();
  	if (IS_ERR(data->cred)) {
f7732d657   Trond Myklebust   NFS: Fix a use-af...
447
  		struct rpc_task *task = ERR_CAST(data->cred);
d3d4152a5   Jeff Layton   nfs: make sillyre...
448
449
450
451
452
453
454
455
456
457
  		kfree(data);
  		return task;
  	}
  
  	msg.rpc_argp = &data->args;
  	msg.rpc_resp = &data->res;
  	msg.rpc_cred = data->cred;
  
  	/* set up nfs_renamedata */
  	data->old_dir = old_dir;
a4118ee1d   Al Viro   a couple of open-...
458
  	ihold(old_dir);
d3d4152a5   Jeff Layton   nfs: make sillyre...
459
  	data->new_dir = new_dir;
a4118ee1d   Al Viro   a couple of open-...
460
  	ihold(new_dir);
d3d4152a5   Jeff Layton   nfs: make sillyre...
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  	data->old_dentry = dget(old_dentry);
  	data->new_dentry = dget(new_dentry);
  	nfs_fattr_init(&data->old_fattr);
  	nfs_fattr_init(&data->new_fattr);
  
  	/* set up nfs_renameargs */
  	data->args.old_dir = NFS_FH(old_dir);
  	data->args.old_name = &old_dentry->d_name;
  	data->args.new_dir = NFS_FH(new_dir);
  	data->args.new_name = &new_dentry->d_name;
  
  	/* set up nfs_renameres */
  	data->res.old_fattr = &data->old_fattr;
  	data->res.new_fattr = &data->new_fattr;
  
  	nfs_sb_active(old_dir->i_sb);
  
  	NFS_PROTO(data->old_dir)->rename_setup(&msg, old_dir);
f7732d657   Trond Myklebust   NFS: Fix a use-af...
479
  	return rpc_run_task(&task_setup_data);
d3d4152a5   Jeff Layton   nfs: make sillyre...
480
  }
779c51795   Jeff Layton   nfs: move nfs_sil...
481
482
483
484
485
486
487
488
489
490
491
492
  /**
   * nfs_sillyrename - Perform a silly-rename of a dentry
   * @dir: inode of directory that contains dentry
   * @dentry: dentry to be sillyrenamed
   *
   * NFSv2/3 is stateless and the server doesn't know when the client is
   * holding a file open. To prevent application problems when a file is
   * unlinked while it's still open, the client performs a "silly-rename".
   * That is, it renames the file to a hidden file in the same directory,
   * and only performs the unlink once the last reference to it is put.
   *
   * The final cleanup is done during dentry_iput.
674e405b8   J. Bruce Fields   nfs: document nfs...
493
494
495
496
497
498
499
500
   *
   * (Note: NFSv4 is stateful, and has opens, so in theory an NFSv4 server
   * could take responsibility for keeping open files referenced.  The server
   * would also need to ensure that opened-but-deleted files were kept over
   * reboots.  However, we may not assume a server does so.  (RFC 5661
   * does provide an OPEN4_RESULT_PRESERVE_UNLINKED flag that a server can
   * use to advertise that it does this; some day we may take advantage of
   * it.))
779c51795   Jeff Layton   nfs: move nfs_sil...
501
502
503
504
505
506
507
508
509
   */
  int
  nfs_sillyrename(struct inode *dir, struct dentry *dentry)
  {
  	static unsigned int sillycounter;
  	const int      fileidsize  = sizeof(NFS_FILEID(dentry->d_inode))*2;
  	const int      countersize = sizeof(sillycounter)*2;
  	const int      slen        = sizeof(".nfs")+fileidsize+countersize-1;
  	char           silly[slen+1];
779c51795   Jeff Layton   nfs: move nfs_sil...
510
  	struct dentry *sdentry;
d3d4152a5   Jeff Layton   nfs: make sillyre...
511
  	struct rpc_task *task;
779c51795   Jeff Layton   nfs: move nfs_sil...
512
513
514
515
516
  	int            error = -EIO;
  
  	dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)
  ",
  		dentry->d_parent->d_name.name, dentry->d_name.name,
b7ab39f63   Nick Piggin   fs: dcache scale ...
517
  		dentry->d_count);
779c51795   Jeff Layton   nfs: move nfs_sil...
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
  	nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
  
  	/*
  	 * We don't allow a dentry to be silly-renamed twice.
  	 */
  	error = -EBUSY;
  	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
  		goto out;
  
  	sprintf(silly, ".nfs%*.*Lx",
  		fileidsize, fileidsize,
  		(unsigned long long)NFS_FILEID(dentry->d_inode));
  
  	/* Return delegation in anticipation of the rename */
  	nfs_inode_return_delegation(dentry->d_inode);
  
  	sdentry = NULL;
  	do {
  		char *suffix = silly + slen - countersize;
  
  		dput(sdentry);
  		sillycounter++;
  		sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
  
  		dfprintk(VFS, "NFS: trying to rename %s to %s
  ",
  				dentry->d_name.name, silly);
  
  		sdentry = lookup_one_len(silly, dentry->d_parent, slen);
  		/*
  		 * N.B. Better to return EBUSY here ... it could be
  		 * dangerous to delete the file while it's in use.
  		 */
  		if (IS_ERR(sdentry))
  			goto out;
  	} while (sdentry->d_inode != NULL); /* need negative lookup */
d3d4152a5   Jeff Layton   nfs: make sillyre...
554
555
556
557
558
559
  	/* queue unlink first. Can't do this from rpc_release as it
  	 * has to allocate memory
  	 */
  	error = nfs_async_unlink(dir, dentry);
  	if (error)
  		goto out_dput;
73ca1001e   Jeff Layton   nfs: don't use d_...
560
561
562
563
564
565
566
  	/* populate unlinkdata with the right dname */
  	error = nfs_copy_dname(sdentry,
  				(struct nfs_unlinkdata *)dentry->d_fsdata);
  	if (error) {
  		nfs_cancel_async_unlink(dentry);
  		goto out_dput;
  	}
d3d4152a5   Jeff Layton   nfs: make sillyre...
567
568
569
570
571
572
  	/* run the rename task, undo unlink if it fails */
  	task = nfs_async_rename(dir, dir, dentry, sdentry);
  	if (IS_ERR(task)) {
  		error = -EBUSY;
  		nfs_cancel_async_unlink(dentry);
  		goto out_dput;
779c51795   Jeff Layton   nfs: move nfs_sil...
573
  	}
d3d4152a5   Jeff Layton   nfs: make sillyre...
574
575
576
577
578
579
580
  
  	/* wait for the RPC task to complete, unless a SIGKILL intervenes */
  	error = rpc_wait_for_completion_task(task);
  	if (error == 0)
  		error = task->tk_status;
  	rpc_put_task(task);
  out_dput:
779c51795   Jeff Layton   nfs: move nfs_sil...
581
582
583
584
  	dput(sdentry);
  out:
  	return error;
  }