diff options
Diffstat (limited to 'fs/nfs/unlink.c')
-rw-r--r-- | fs/nfs/unlink.c | 38 |
1 files changed, 28 insertions, 10 deletions
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 60395ad3a2e4..bb939edd4c99 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include "iostat.h" | 20 | #include "iostat.h" |
21 | #include "delegation.h" | 21 | #include "delegation.h" |
22 | 22 | ||
23 | #include "nfstrace.h" | ||
24 | |||
23 | /** | 25 | /** |
24 | * nfs_free_unlinkdata - release data from a sillydelete operation. | 26 | * nfs_free_unlinkdata - release data from a sillydelete operation. |
25 | * @data: pointer to unlink structure. | 27 | * @data: pointer to unlink structure. |
@@ -77,6 +79,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) | |||
77 | struct nfs_unlinkdata *data = calldata; | 79 | struct nfs_unlinkdata *data = calldata; |
78 | struct inode *dir = data->dir; | 80 | struct inode *dir = data->dir; |
79 | 81 | ||
82 | trace_nfs_sillyrename_unlink(data, task->tk_status); | ||
80 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) | 83 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) |
81 | rpc_restart_call_prepare(task); | 84 | rpc_restart_call_prepare(task); |
82 | } | 85 | } |
@@ -204,6 +207,13 @@ out_free: | |||
204 | return ret; | 207 | return ret; |
205 | } | 208 | } |
206 | 209 | ||
210 | void nfs_wait_on_sillyrename(struct dentry *dentry) | ||
211 | { | ||
212 | struct nfs_inode *nfsi = NFS_I(dentry->d_inode); | ||
213 | |||
214 | wait_event(nfsi->waitqueue, atomic_read(&nfsi->silly_count) <= 1); | ||
215 | } | ||
216 | |||
207 | void nfs_block_sillyrename(struct dentry *dentry) | 217 | void nfs_block_sillyrename(struct dentry *dentry) |
208 | { | 218 | { |
209 | struct nfs_inode *nfsi = NFS_I(dentry->d_inode); | 219 | struct nfs_inode *nfsi = NFS_I(dentry->d_inode); |
@@ -336,6 +346,8 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata) | |||
336 | struct inode *new_dir = data->new_dir; | 346 | struct inode *new_dir = data->new_dir; |
337 | struct dentry *old_dentry = data->old_dentry; | 347 | struct dentry *old_dentry = data->old_dentry; |
338 | 348 | ||
349 | trace_nfs_sillyrename_rename(old_dir, old_dentry, | ||
350 | new_dir, data->new_dentry, task->tk_status); | ||
339 | if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) { | 351 | if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) { |
340 | rpc_restart_call_prepare(task); | 352 | rpc_restart_call_prepare(task); |
341 | return; | 353 | return; |
@@ -444,6 +456,14 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, | |||
444 | return rpc_run_task(&task_setup_data); | 456 | return rpc_run_task(&task_setup_data); |
445 | } | 457 | } |
446 | 458 | ||
459 | #define SILLYNAME_PREFIX ".nfs" | ||
460 | #define SILLYNAME_PREFIX_LEN ((unsigned)sizeof(SILLYNAME_PREFIX) - 1) | ||
461 | #define SILLYNAME_FILEID_LEN ((unsigned)sizeof(u64) << 1) | ||
462 | #define SILLYNAME_COUNTER_LEN ((unsigned)sizeof(unsigned int) << 1) | ||
463 | #define SILLYNAME_LEN (SILLYNAME_PREFIX_LEN + \ | ||
464 | SILLYNAME_FILEID_LEN + \ | ||
465 | SILLYNAME_COUNTER_LEN) | ||
466 | |||
447 | /** | 467 | /** |
448 | * nfs_sillyrename - Perform a silly-rename of a dentry | 468 | * nfs_sillyrename - Perform a silly-rename of a dentry |
449 | * @dir: inode of directory that contains dentry | 469 | * @dir: inode of directory that contains dentry |
@@ -469,10 +489,8 @@ int | |||
469 | nfs_sillyrename(struct inode *dir, struct dentry *dentry) | 489 | nfs_sillyrename(struct inode *dir, struct dentry *dentry) |
470 | { | 490 | { |
471 | static unsigned int sillycounter; | 491 | static unsigned int sillycounter; |
472 | const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2; | 492 | unsigned char silly[SILLYNAME_LEN + 1]; |
473 | const int countersize = sizeof(sillycounter)*2; | 493 | unsigned long long fileid; |
474 | const int slen = sizeof(".nfs")+fileidsize+countersize-1; | ||
475 | char silly[slen+1]; | ||
476 | struct dentry *sdentry; | 494 | struct dentry *sdentry; |
477 | struct rpc_task *task; | 495 | struct rpc_task *task; |
478 | int error = -EIO; | 496 | int error = -EIO; |
@@ -489,20 +507,20 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
489 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) | 507 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) |
490 | goto out; | 508 | goto out; |
491 | 509 | ||
492 | sprintf(silly, ".nfs%*.*Lx", | 510 | fileid = NFS_FILEID(dentry->d_inode); |
493 | fileidsize, fileidsize, | ||
494 | (unsigned long long)NFS_FILEID(dentry->d_inode)); | ||
495 | 511 | ||
496 | /* Return delegation in anticipation of the rename */ | 512 | /* Return delegation in anticipation of the rename */ |
497 | NFS_PROTO(dentry->d_inode)->return_delegation(dentry->d_inode); | 513 | NFS_PROTO(dentry->d_inode)->return_delegation(dentry->d_inode); |
498 | 514 | ||
499 | sdentry = NULL; | 515 | sdentry = NULL; |
500 | do { | 516 | do { |
501 | char *suffix = silly + slen - countersize; | 517 | int slen; |
502 | |||
503 | dput(sdentry); | 518 | dput(sdentry); |
504 | sillycounter++; | 519 | sillycounter++; |
505 | sprintf(suffix, "%*.*x", countersize, countersize, sillycounter); | 520 | slen = scnprintf(silly, sizeof(silly), |
521 | SILLYNAME_PREFIX "%0*llx%0*x", | ||
522 | SILLYNAME_FILEID_LEN, fileid, | ||
523 | SILLYNAME_COUNTER_LEN, sillycounter); | ||
506 | 524 | ||
507 | dfprintk(VFS, "NFS: trying to rename %s to %s\n", | 525 | dfprintk(VFS, "NFS: trying to rename %s to %s\n", |
508 | dentry->d_name.name, silly); | 526 | dentry->d_name.name, silly); |