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 nfs_async_unlink_init(struct rpc_task *task, void *calldata) 91 { 92 struct nfs_unlinkdata *data = calldata; 93 struct dentry *dir = data->dir; 94 struct rpc_message msg = { 95 .rpc_cred = data->cred, 96 }; 97 int status = -ENOENT; 98 99 if (!data->name.len) 100 goto out_err; 101 102 status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name); 103 if (status < 0) 104 goto out_err; 105 nfs_begin_data_update(dir->d_inode); 106 rpc_call_setup(task, &msg, 0); 107 return; 108 out_err: 109 rpc_exit(task, status); 110 } 111 112 /** 113 * nfs_async_unlink_done - Sillydelete post-processing 114 * @task: rpc_task of the sillydelete 115 * 116 * Do the directory attribute update. 117 */ 118 static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) 119 { 120 struct nfs_unlinkdata *data = calldata; 121 struct dentry *dir = data->dir; 122 struct inode *dir_i; 123 124 if (!dir) 125 return; 126 dir_i = dir->d_inode; 127 nfs_end_data_update(dir_i); 128 if (NFS_PROTO(dir_i)->unlink_done(dir, task)) 129 return; 130 put_rpccred(data->cred); 131 data->cred = NULL; 132 dput(dir); 133 } 134 135 /** 136 * nfs_async_unlink_release - Release the sillydelete data. 137 * @task: rpc_task of the sillydelete 138 * 139 * We need to call nfs_put_unlinkdata as a 'tk_release' task since the 140 * rpc_task would be freed too. 141 */ 142 static void nfs_async_unlink_release(void *calldata) 143 { 144 struct nfs_unlinkdata *data = calldata; 145 nfs_put_unlinkdata(data); 146 } 147 148 static const struct rpc_call_ops nfs_unlink_ops = { 149 .rpc_call_prepare = nfs_async_unlink_init, 150 .rpc_call_done = nfs_async_unlink_done, 151 .rpc_release = nfs_async_unlink_release, 152 }; 153 154 /** 155 * nfs_async_unlink - asynchronous unlinking of a file 156 * @dentry: dentry to unlink 157 */ 158 int 159 nfs_async_unlink(struct dentry *dentry) 160 { 161 struct dentry *dir = dentry->d_parent; 162 struct nfs_unlinkdata *data; 163 struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode); 164 int status = -ENOMEM; 165 166 data = kzalloc(sizeof(*data), GFP_KERNEL); 167 if (!data) 168 goto out; 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 rpc_init_task(&data->task, clnt, RPC_TASK_ASYNC, &nfs_unlink_ops, data); 183 184 spin_lock(&dentry->d_lock); 185 dentry->d_flags |= DCACHE_NFSFS_RENAMED; 186 spin_unlock(&dentry->d_lock); 187 188 rpc_sleep_on(&nfs_delete_queue, &data->task, NULL, NULL); 189 status = 0; 190 out: 191 return status; 192 out_free: 193 kfree(data); 194 return status; 195 } 196 197 /** 198 * nfs_complete_unlink - Initialize completion of the sillydelete 199 * @dentry: dentry to delete 200 * 201 * Since we're most likely to be called by dentry_iput(), we 202 * only use the dentry to find the sillydelete. We then copy the name 203 * into the qstr. 204 */ 205 void 206 nfs_complete_unlink(struct dentry *dentry) 207 { 208 struct nfs_unlinkdata *data; 209 210 for(data = nfs_deletes; data != NULL; data = data->next) { 211 if (dentry == data->dentry) 212 break; 213 } 214 if (!data) 215 return; 216 data->count++; 217 nfs_copy_dname(dentry, data); 218 spin_lock(&dentry->d_lock); 219 dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; 220 spin_unlock(&dentry->d_lock); 221 rpc_wake_up_task(&data->task); 222 nfs_put_unlinkdata(data); 223 } 224