aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/unlink.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2010-09-17 17:31:57 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-09-17 17:31:57 -0400
commitd3d4152a5d59af9e13a73efa9e9c24383fbe307f (patch)
tree552ea5586bb64f8fef93825c72e88b9248d02b79 /fs/nfs/unlink.c
parent779c51795bfb35c2403c924b9de90ca9356bc693 (diff)
nfs: make sillyrename an async operation
A synchronous rename can be interrupted by a SIGKILL. If that happens during a sillyrename operation, it's possible for the rename call to be sent to the server, but the task exits before processing the reply. If this happens, the sillyrenamed file won't get cleaned up during nfs_dentry_iput and the server is left with a dangling .nfs* file hanging around. Fix this problem by turning sillyrename into an asynchronous operation and have the task doing the sillyrename just wait on the reply. If the task is killed before the sillyrename completes, it'll still proceed to completion. Signed-off-by: Jeff Layton <jlayton@redhat.com> Reviewed-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/unlink.c')
-rw-r--r--fs/nfs/unlink.c200
1 files changed, 189 insertions, 11 deletions
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index c3ce865294f1..698b3e6367ff 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -307,6 +307,174 @@ nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
307 nfs_free_unlinkdata(data); 307 nfs_free_unlinkdata(data);
308} 308}
309 309
310/* Cancel a queued async unlink. Called when a sillyrename run fails. */
311static void
312nfs_cancel_async_unlink(struct dentry *dentry)
313{
314 spin_lock(&dentry->d_lock);
315 if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
316 struct nfs_unlinkdata *data = dentry->d_fsdata;
317
318 dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
319 spin_unlock(&dentry->d_lock);
320 nfs_free_unlinkdata(data);
321 return;
322 }
323 spin_unlock(&dentry->d_lock);
324}
325
326struct nfs_renamedata {
327 struct nfs_renameargs args;
328 struct nfs_renameres res;
329 struct rpc_cred *cred;
330 struct inode *old_dir;
331 struct dentry *old_dentry;
332 struct nfs_fattr old_fattr;
333 struct inode *new_dir;
334 struct dentry *new_dentry;
335 struct nfs_fattr new_fattr;
336};
337
338/**
339 * nfs_async_rename_done - Sillyrename post-processing
340 * @task: rpc_task of the sillyrename
341 * @calldata: nfs_renamedata for the sillyrename
342 *
343 * Do the directory attribute updates and the d_move
344 */
345static void nfs_async_rename_done(struct rpc_task *task, void *calldata)
346{
347 struct nfs_renamedata *data = calldata;
348 struct inode *old_dir = data->old_dir;
349 struct inode *new_dir = data->new_dir;
350
351 if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) {
352 nfs_restart_rpc(task, NFS_SERVER(old_dir)->nfs_client);
353 return;
354 }
355
356 if (task->tk_status != 0) {
357 nfs_cancel_async_unlink(data->old_dentry);
358 return;
359 }
360
361 nfs_set_verifier(data->old_dentry, nfs_save_change_attribute(old_dir));
362 d_move(data->old_dentry, data->new_dentry);
363}
364
365/**
366 * nfs_async_rename_release - Release the sillyrename data.
367 * @calldata: the struct nfs_renamedata to be released
368 */
369static void nfs_async_rename_release(void *calldata)
370{
371 struct nfs_renamedata *data = calldata;
372 struct super_block *sb = data->old_dir->i_sb;
373
374 if (data->old_dentry->d_inode)
375 nfs_mark_for_revalidate(data->old_dentry->d_inode);
376
377 dput(data->old_dentry);
378 dput(data->new_dentry);
379 iput(data->old_dir);
380 iput(data->new_dir);
381 nfs_sb_deactive(sb);
382 put_rpccred(data->cred);
383 kfree(data);
384}
385
386#if defined(CONFIG_NFS_V4_1)
387static void nfs_rename_prepare(struct rpc_task *task, void *calldata)
388{
389 struct nfs_renamedata *data = calldata;
390 struct nfs_server *server = NFS_SERVER(data->old_dir);
391
392 if (nfs4_setup_sequence(server, &data->args.seq_args,
393 &data->res.seq_res, 1, task))
394 return;
395 rpc_call_start(task);
396}
397#endif /* CONFIG_NFS_V4_1 */
398
399static const struct rpc_call_ops nfs_rename_ops = {
400 .rpc_call_done = nfs_async_rename_done,
401 .rpc_release = nfs_async_rename_release,
402#if defined(CONFIG_NFS_V4_1)
403 .rpc_call_prepare = nfs_rename_prepare,
404#endif /* CONFIG_NFS_V4_1 */
405};
406
407/**
408 * nfs_async_rename - perform an asynchronous rename operation
409 * @old_dir: directory that currently holds the dentry to be renamed
410 * @new_dir: target directory for the rename
411 * @old_dentry: original dentry to be renamed
412 * @new_dentry: dentry to which the old_dentry should be renamed
413 *
414 * It's expected that valid references to the dentries and inodes are held
415 */
416static struct rpc_task *
417nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
418 struct dentry *old_dentry, struct dentry *new_dentry)
419{
420 struct nfs_renamedata *data;
421 struct rpc_message msg = { };
422 struct rpc_task_setup task_setup_data = {
423 .rpc_message = &msg,
424 .callback_ops = &nfs_rename_ops,
425 .workqueue = nfsiod_workqueue,
426 .rpc_client = NFS_CLIENT(old_dir),
427 .flags = RPC_TASK_ASYNC,
428 };
429 struct rpc_task *task;
430
431 data = kmalloc(sizeof(*data), GFP_KERNEL);
432 if (data == NULL)
433 return ERR_PTR(-ENOMEM);
434 task_setup_data.callback_data = data,
435
436 data->cred = rpc_lookup_cred();
437 if (IS_ERR(data->cred)) {
438 task = (struct rpc_task *)data->cred;
439 kfree(data);
440 return task;
441 }
442
443 msg.rpc_argp = &data->args;
444 msg.rpc_resp = &data->res;
445 msg.rpc_cred = data->cred;
446
447 /* set up nfs_renamedata */
448 data->old_dir = old_dir;
449 atomic_inc(&old_dir->i_count);
450 data->new_dir = new_dir;
451 atomic_inc(&new_dir->i_count);
452 data->old_dentry = dget(old_dentry);
453 data->new_dentry = dget(new_dentry);
454 nfs_fattr_init(&data->old_fattr);
455 nfs_fattr_init(&data->new_fattr);
456
457 /* set up nfs_renameargs */
458 data->args.old_dir = NFS_FH(old_dir);
459 data->args.old_name = &old_dentry->d_name;
460 data->args.new_dir = NFS_FH(new_dir);
461 data->args.new_name = &new_dentry->d_name;
462
463 /* set up nfs_renameres */
464 data->res.old_fattr = &data->old_fattr;
465 data->res.new_fattr = &data->new_fattr;
466
467 nfs_sb_active(old_dir->i_sb);
468
469 NFS_PROTO(data->old_dir)->rename_setup(&msg, old_dir);
470
471 task = rpc_run_task(&task_setup_data);
472 if (IS_ERR(task))
473 nfs_async_rename_release(data);
474
475 return task;
476}
477
310/** 478/**
311 * nfs_sillyrename - Perform a silly-rename of a dentry 479 * nfs_sillyrename - Perform a silly-rename of a dentry
312 * @dir: inode of directory that contains dentry 480 * @dir: inode of directory that contains dentry
@@ -328,8 +496,8 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
328 const int countersize = sizeof(sillycounter)*2; 496 const int countersize = sizeof(sillycounter)*2;
329 const int slen = sizeof(".nfs")+fileidsize+countersize-1; 497 const int slen = sizeof(".nfs")+fileidsize+countersize-1;
330 char silly[slen+1]; 498 char silly[slen+1];
331 struct qstr qsilly;
332 struct dentry *sdentry; 499 struct dentry *sdentry;
500 struct rpc_task *task;
333 int error = -EIO; 501 int error = -EIO;
334 502
335 dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", 503 dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
@@ -371,17 +539,27 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
371 goto out; 539 goto out;
372 } while (sdentry->d_inode != NULL); /* need negative lookup */ 540 } while (sdentry->d_inode != NULL); /* need negative lookup */
373 541
374 qsilly.name = silly; 542 /* queue unlink first. Can't do this from rpc_release as it
375 qsilly.len = strlen(silly); 543 * has to allocate memory
376 error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly); 544 */
377 if (dentry->d_inode) 545 error = nfs_async_unlink(dir, dentry);
378 nfs_mark_for_revalidate(dentry->d_inode); 546 if (error)
379 if (!error) { 547 goto out_dput;
380 nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 548
381 d_move(dentry, sdentry); 549 /* run the rename task, undo unlink if it fails */
382 error = nfs_async_unlink(dir, dentry); 550 task = nfs_async_rename(dir, dir, dentry, sdentry);
383 /* If we return 0 we don't unlink */ 551 if (IS_ERR(task)) {
552 error = -EBUSY;
553 nfs_cancel_async_unlink(dentry);
554 goto out_dput;
384 } 555 }
556
557 /* wait for the RPC task to complete, unless a SIGKILL intervenes */
558 error = rpc_wait_for_completion_task(task);
559 if (error == 0)
560 error = task->tk_status;
561 rpc_put_task(task);
562out_dput:
385 dput(sdentry); 563 dput(sdentry);
386out: 564out:
387 return error; 565 return error;