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 0 : {
36 0 : struct nfs_unlinkdata **q;
37 :
38 0 : for (q = &nfs_deletes; *q != NULL; q = &((*q)->next)) {
39 0 : if (*q == data) {
40 0 : *q = data->next;
41 0 : 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 0 : {
53 0 : if (--data->count == 0) {
54 0 : nfs_detach_unlinkdata(data);
55 0 : if (data->name.name != NULL)
56 0 : kfree(data->name.name);
57 0 : 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 0 : {
70 0 : char *str;
71 0 : int len = dentry->d_name.len;
72 :
73 0 : str = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL);
74 0 : if (!str)
75 : return;
76 0 : memcpy(str, dentry->d_name.name, len);
77 0 : if (!data->name.len) {
78 0 : data->name.len = len;
79 0 : data->name.name = str;
80 : } else
81 0 : 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 0 : {
94 0 : struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata;
95 0 : struct dentry *dir = data->dir;
96 0 : struct rpc_message msg = {
97 : .rpc_cred = data->cred,
98 0 : };
99 0 : int status = -ENOENT;
100 :
101 0 : if (!data->name.len)
102 0 : goto out_err;
103 :
104 0 : status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name);
105 0 : if (status < 0)
106 0 : goto out_err;
107 0 : nfs_begin_data_update(dir->d_inode);
108 0 : rpc_call_setup(task, &msg, 0);
109 0 : return;
110 : out_err:
111 0 : 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 0 : {
123 0 : struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata;
124 0 : struct dentry *dir = data->dir;
125 0 : struct inode *dir_i;
126 :
127 0 : if (!dir)
128 0 : return;
129 0 : dir_i = dir->d_inode;
130 0 : nfs_end_data_update(dir_i);
131 0 : if (NFS_PROTO(dir_i)->unlink_done(dir, task))
132 0 : return;
133 0 : put_rpccred(data->cred);
134 0 : data->cred = NULL;
135 0 : 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 0 : {
148 0 : struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata;
149 0 : 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 0 : {
159 0 : struct dentry *dir = dentry->d_parent;
160 0 : struct nfs_unlinkdata *data;
161 0 : struct rpc_task *task;
162 0 : struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode);
163 0 : int status = -ENOMEM;
164 :
165 0 : data = kmalloc(sizeof(*data), GFP_KERNEL);
166 0 : if (!data)
167 0 : goto out;
168 0 : memset(data, 0, sizeof(*data));
169 :
170 0 : data->cred = rpcauth_lookupcred(clnt->cl_auth, 0);
171 0 : if (IS_ERR(data->cred)) {
172 0 : status = PTR_ERR(data->cred);
173 0 : goto out_free;
174 : }
175 0 : data->dir = dget(dir);
176 0 : data->dentry = dentry;
177 :
178 0 : data->next = nfs_deletes;
179 0 : nfs_deletes = data;
180 0 : data->count = 1;
181 :
182 0 : task = &data->task;
183 0 : rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC);
184 0 : task->tk_calldata = data;
185 0 : task->tk_action = nfs_async_unlink_init;
186 0 : task->tk_release = nfs_async_unlink_release;
187 :
188 0 : spin_lock(&dentry->d_lock);
189 0 : dentry->d_flags |= DCACHE_NFSFS_RENAMED;
190 0 : spin_unlock(&dentry->d_lock);
191 :
192 0 : rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL);
193 0 : status = 0;
194 : out:
195 0 : return status;
196 : out_free:
197 0 : kfree(data);
198 0 : 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 0 : {
212 0 : struct nfs_unlinkdata *data;
213 :
214 0 : for(data = nfs_deletes; data != NULL; data = data->next) {
215 0 : if (dentry == data->dentry)
216 0 : break;
217 : }
218 0 : if (!data)
219 0 : return;
220 0 : data->count++;
221 0 : nfs_copy_dname(dentry, data);
222 0 : spin_lock(&dentry->d_lock);
223 0 : dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
224 0 : spin_unlock(&dentry->d_lock);
225 0 : rpc_wake_up_task(&data->task);
226 0 : nfs_put_unlinkdata(data);
227 : }
|