1 /* 2 * linux/fs/nfs/unlink.c 3 * 4 * nfs sillydelete handling 5 * 6 * NOTE: we rely on holding the BKL for list manipulation protection. 7 */ 8 9 #include <linux/slab.h> 10 #include <linux/string.h> 11 #include <linux/dcache.h> 12 #include <linux/sunrpc/sched.h> 13 #include <linux/sunrpc/clnt.h> 14 #include <linux/nfs_fs.h> 15 16 17 struct nfs_unlinkdata { 18 struct nfs_unlinkdata *next; 19 struct dentry *dir, *dentry; 20 struct qstr name; 21 struct rpc_task task; 22 struct rpc_cred *cred; 23 unsigned int count; 24 }; 25 26 static struct nfs_unlinkdata *nfs_deletes; 27 static 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 */ 33 static inline void 34 nfs_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 /** 47 * nfs_put_unlinkdata - release data from a sillydelete operation. 48 * @data: pointer to unlink structure. 49 */ 50 static void 51 nfs_put_unlinkdata(struct nfs_unlinkdata *data) 52 { 53 if (--data->count == 0) { 54 nfs_detach_unlinkdata(data); 55 if (data->name.name != NULL) 56 kfree(data->name.name); 57 kfree(data); 58 } 59 } 60 61 #define NAME_ALLOC_LEN(len) ((len+16) & ~15) 62 /** 63 * nfs_copy_dname - copy dentry name to data structure 64 * @dentry: pointer to dentry 65 * @data: nfs_unlinkdata 66 */ 67 static inline void 68 nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data) 69 { 70 char *str; 71 int len = dentry->d_name.len; 72 73 str = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL); 74 if (!str) 75 return; 76 memcpy(str, dentry->d_name.name, len); 77 if (!data->name.len) { 78 data->name.len = len; 79 data->name.name = str; 80 } else 81 kfree(str); 82 } 83 84 /** 85 * nfs_async_unlink_init - Initialize the RPC info 86 * @task: rpc_task of the sillydelete 87 * 88 * We delay initializing RPC info until after the call to dentry_iput() 89 * in order to minimize races against rename(). 90 */ 91 static void 92 nfs_async_unlink_init(struct rpc_task *task) 93 { 94 struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; 95 struct dentry *dir = data->dir; 96 struct rpc_message msg = { 97 .rpc_cred = data->cred, 98 }; 99 int status = -ENOENT; 100 101 if (!data->name.len) 102 goto out_err; 103 104 status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name); 105 if (status < 0) 106 goto out_err; 107 nfs_begin_data_update(dir->d_inode); 108 rpc_call_setup(task, &msg, 0); 109 return; 110 out_err: 111 rpc_exit(task, status); 112 } 113 114 /** 115 * nfs_async_unlink_done - Sillydelete post-processing 116 * @task: rpc_task of the sillydelete 117 * 118 * Do the directory attribute update. 119 */ 120 static void 121 nfs_async_unlink_done(struct rpc_task *task) 122 { 123 struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; 124 struct dentry *dir = data->dir; 125 struct inode *dir_i; 126 127 if (!dir) 128 return; 129 dir_i = dir->d_inode; 130 nfs_end_data_update(dir_i); 131 if (NFS_PROTO(dir_i)->unlink_done(dir, task)) 132 return; 133 put_rpccred(data->cred); 134 data->cred = NULL; 135 dput(dir); 136 } 137 138 /** 139 * nfs_async_unlink_release - Release the sillydelete data. 140 * @task: rpc_task of the sillydelete 141 * 142 * We need to call nfs_put_unlinkdata as a 'tk_release' task since the 143 * rpc_task would be freed too. 144 */ 145 static void 146 nfs_async_unlink_release(struct rpc_task *task) 147 { 148 struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; 149 nfs_put_unlinkdata(data); 150 } 151 152 /** 153 * nfs_async_unlink - asynchronous unlinking of a file 154 * @dentry: dentry to unlink 155 */ 156 int 157 nfs_async_unlink(struct dentry *dentry) 158 { 159 struct dentry *dir = dentry->d_parent; 160 struct nfs_unlinkdata *data; 161 struct rpc_task *task; 162 struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode); 163 int status = -ENOMEM; 164 165 data = kmalloc(sizeof(*data), GFP_KERNEL); 166 if (!data) 167 goto out; 168 memset(data, 0, sizeof(*data)); 169 170 data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); 171 if (IS_ERR(data->cred)) { 172 status = PTR_ERR(data->cred); 173 goto out_free; 174 } 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 task = &data->task; 183 rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC); 184 task->tk_calldata = data; 185 task->tk_action = nfs_async_unlink_init; 186 task->tk_release = nfs_async_unlink_release; 187 188 spin_lock(&dentry->d_lock); 189 dentry->d_flags |= DCACHE_NFSFS_RENAMED; 190 spin_unlock(&dentry->d_lock); 191 192 rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL); 193 status = 0; 194 out: 195 return status; 196 out_free: 197 kfree(data); 198 return status; 199 } 200 201 /** 202 * nfs_complete_unlink - Initialize completion of the sillydelete 203 * @dentry: dentry to delete 204 * 205 * Since we're most likely to be called by dentry_iput(), we 206 * only use the dentry to find the sillydelete. We then copy the name 207 * into the qstr. 208 */ 209 void 210 nfs_complete_unlink(struct dentry *dentry) 211 { 212 struct nfs_unlinkdata *data; 213 214 for(data = nfs_deletes; data != NULL; data = data->next) { 215 if (dentry == data->dentry) 216 break; 217 } 218 if (!data) 219 return; 220 data->count++; 221 nfs_copy_dname(dentry, data); 222 spin_lock(&dentry->d_lock); 223 dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; 224 spin_unlock(&dentry->d_lock); 225 rpc_wake_up_task(&data->task); 226 nfs_put_unlinkdata(data); 227 } 228