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