An interrupted rename will leave the old dentry behind if the rename succeeds. Fix this by forcing a lookup the next time through ->d_revalidate. A previous attempt at solving this problem took the approach to complete the work of the rename asynchronously, however that approach was wrong since it would allow the d_move() to occur after the directory's i_mutex had been dropped by the original process.
Unified · Split
| @@ -2056,7 +2056,11 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, · 2055 unmodified lines | |||
| 2056 | } | 2056 | } |
| 2057 | 2057 | ||
| 2058 | error = rpc_wait_for_completion_task(task); | 2058 | error = rpc_wait_for_completion_task(task); |
| 2059 | if (error == 0) | 2059 | if (error != 0) { |
| 2060 | ((struct nfs_renamedata *)task->tk_calldata)->cancelled = 1; | ||
| 2061 | /* Paired with the atomic_dec_and_test() barrier in rpc_do_put_task() */ | ||
| 2062 | smp_wmb(); | ||
| 2063 | } else | ||
| 2060 | error = task->tk_status; | 2064 | error = task->tk_status; |
| 2061 | rpc_put_task(task); | 2065 | rpc_put_task(task); |
| 2062 | out: | 2066 | out: |
| @@ -288,6 +288,19 @@ static void nfs_async_rename_release(void *calldata) · 287 unmodified lines | |||
| 288 | if (d_really_is_positive(data->old_dentry)) | 288 | if (d_really_is_positive(data->old_dentry)) |
| 289 | nfs_mark_for_revalidate(d_inode(data->old_dentry)); | 289 | nfs_mark_for_revalidate(d_inode(data->old_dentry)); |
| 290 | 290 | ||
| 291 | /* The result of the rename is unknown. Play it safe by | ||
| 292 | * forcing a new lookup */ | ||
| 293 | if (data->cancelled) { | ||
| 294 | spin_lock(&data->old_dir->i_lock); | ||
| 295 | nfs_force_lookup_revalidate(data->old_dir); | ||
| 296 | spin_unlock(&data->old_dir->i_lock); | ||
| 297 | if (data->new_dir != data->old_dir) { | ||
| 298 | spin_lock(&data->new_dir->i_lock); | ||
| 299 | nfs_force_lookup_revalidate(data->new_dir); | ||
| 300 | spin_unlock(&data->new_dir->i_lock); | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 291 | dput(data->old_dentry); | 304 | dput(data->old_dentry); |
| 292 | dput(data->new_dentry); | 305 | dput(data->new_dentry); |
| 293 | iput(data->old_dir); | 306 | iput(data->old_dir); |
| @@ -1533,6 +1533,7 @@ struct nfs_renamedata { · 1532 unmodified lines | |||
| 1533 | struct nfs_fattr new_fattr; | 1533 | struct nfs_fattr new_fattr; |
| 1534 | void (*complete)(struct rpc_task *, struct nfs_renamedata *); | 1534 | void (*complete)(struct rpc_task *, struct nfs_renamedata *); |
| 1535 | long timeout; | 1535 | long timeout; |
| 1536 | bool cancelled; | ||
| 1536 | }; | 1537 | }; |
| 1537 | 1538 | ||
| 1538 | struct nfs_access_entry; | 1539 | struct nfs_access_entry; |