Avoid compile error in fs/nfs/unlink.c
[safe/jmp/linux-2.6] / fs / nfs / unlink.c
1 /*
2  *  linux/fs/nfs/unlink.c
3  *
4  * nfs sillydelete handling
5  *
6  */
7
8 #include <linux/slab.h>
9 #include <linux/string.h>
10 #include <linux/dcache.h>
11 #include <linux/sunrpc/sched.h>
12 #include <linux/sunrpc/clnt.h>
13 #include <linux/nfs_fs.h>
14 #include <linux/sched.h>
15 #include <linux/wait.h>
16
17 struct nfs_unlinkdata {
18         struct hlist_node list;
19         struct nfs_removeargs args;
20         struct nfs_removeres res;
21         struct inode *dir;
22         struct rpc_cred *cred;
23 };
24
25 /**
26  * nfs_free_unlinkdata - release data from a sillydelete operation.
27  * @data: pointer to unlink structure.
28  */
29 static void
30 nfs_free_unlinkdata(struct nfs_unlinkdata *data)
31 {
32         iput(data->dir);
33         put_rpccred(data->cred);
34         kfree(data->args.name.name);
35         kfree(data);
36 }
37
38 #define NAME_ALLOC_LEN(len)     ((len+16) & ~15)
39 /**
40  * nfs_copy_dname - copy dentry name to data structure
41  * @dentry: pointer to dentry
42  * @data: nfs_unlinkdata
43  */
44 static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
45 {
46         char            *str;
47         int             len = dentry->d_name.len;
48
49         str = kmemdup(dentry->d_name.name, NAME_ALLOC_LEN(len), GFP_KERNEL);
50         if (!str)
51                 return -ENOMEM;
52         data->args.name.len = len;
53         data->args.name.name = str;
54         return 0;
55 }
56
57 static void nfs_free_dname(struct nfs_unlinkdata *data)
58 {
59         kfree(data->args.name.name);
60         data->args.name.name = NULL;
61         data->args.name.len = 0;
62 }
63
64 static void nfs_dec_sillycount(struct inode *dir)
65 {
66         struct nfs_inode *nfsi = NFS_I(dir);
67         if (atomic_dec_return(&nfsi->silly_count) == 1)
68                 wake_up(&nfsi->waitqueue);
69 }
70
71 /**
72  * nfs_async_unlink_init - Initialize the RPC info
73  * task: rpc_task of the sillydelete
74  */
75 static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
76 {
77         struct nfs_unlinkdata *data = calldata;
78         struct inode *dir = data->dir;
79         struct rpc_message msg = {
80                 .rpc_argp = &data->args,
81                 .rpc_resp = &data->res,
82                 .rpc_cred = data->cred,
83         };
84
85         NFS_PROTO(dir)->unlink_setup(&msg, dir);
86         rpc_call_setup(task, &msg, 0);
87 }
88
89 /**
90  * nfs_async_unlink_done - Sillydelete post-processing
91  * @task: rpc_task of the sillydelete
92  *
93  * Do the directory attribute update.
94  */
95 static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
96 {
97         struct nfs_unlinkdata *data = calldata;
98         struct inode *dir = data->dir;
99
100         if (!NFS_PROTO(dir)->unlink_done(task, dir))
101                 rpc_restart_call(task);
102 }
103
104 /**
105  * nfs_async_unlink_release - Release the sillydelete data.
106  * @task: rpc_task of the sillydelete
107  *
108  * We need to call nfs_put_unlinkdata as a 'tk_release' task since the
109  * rpc_task would be freed too.
110  */
111 static void nfs_async_unlink_release(void *calldata)
112 {
113         struct nfs_unlinkdata   *data = calldata;
114
115         nfs_dec_sillycount(data->dir);
116         nfs_free_unlinkdata(data);
117 }
118
119 static const struct rpc_call_ops nfs_unlink_ops = {
120         .rpc_call_prepare = nfs_async_unlink_init,
121         .rpc_call_done = nfs_async_unlink_done,
122         .rpc_release = nfs_async_unlink_release,
123 };
124
125 static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data)
126 {
127         struct rpc_task *task;
128         struct dentry *alias;
129
130         alias = d_lookup(parent, &data->args.name);
131         if (alias != NULL) {
132                 int ret = 0;
133                 /*
134                  * Hey, we raced with lookup... See if we need to transfer
135                  * the sillyrename information to the aliased dentry.
136                  */
137                 nfs_free_dname(data);
138                 spin_lock(&alias->d_lock);
139                 if (!(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
140                         alias->d_fsdata = data;
141                         alias->d_flags ^= DCACHE_NFSFS_RENAMED;
142                         ret = 1;
143                 }
144                 spin_unlock(&alias->d_lock);
145                 nfs_dec_sillycount(dir);
146                 dput(alias);
147                 return ret;
148         }
149         data->dir = igrab(dir);
150         if (!data->dir) {
151                 nfs_dec_sillycount(dir);
152                 return 0;
153         }
154         data->args.fh = NFS_FH(dir);
155         nfs_fattr_init(&data->res.dir_attr);
156
157         task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data);
158         if (!IS_ERR(task))
159                 rpc_put_task(task);
160         return 1;
161 }
162
163 static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
164 {
165         struct dentry *parent;
166         struct inode *dir;
167         int ret = 0;
168
169
170         parent = dget_parent(dentry);
171         if (parent == NULL)
172                 goto out_free;
173         dir = parent->d_inode;
174         if (nfs_copy_dname(dentry, data) == 0)
175                 goto out_dput;
176         /* Non-exclusive lock protects against concurrent lookup() calls */
177         spin_lock(&dir->i_lock);
178         if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) == 0) {
179                 /* Deferred delete */
180                 hlist_add_head(&data->list, &NFS_I(dir)->silly_list);
181                 spin_unlock(&dir->i_lock);
182                 ret = 1;
183                 goto out_dput;
184         }
185         spin_unlock(&dir->i_lock);
186         ret = nfs_do_call_unlink(parent, dir, data);
187 out_dput:
188         dput(parent);
189 out_free:
190         return ret;
191 }
192
193 void nfs_block_sillyrename(struct dentry *dentry)
194 {
195         struct nfs_inode *nfsi = NFS_I(dentry->d_inode);
196
197         wait_event(nfsi->waitqueue, atomic_cmpxchg(&nfsi->silly_count, 1, 0) == 1);
198 }
199
200 void nfs_unblock_sillyrename(struct dentry *dentry)
201 {
202         struct inode *dir = dentry->d_inode;
203         struct nfs_inode *nfsi = NFS_I(dir);
204         struct nfs_unlinkdata *data;
205
206         atomic_inc(&nfsi->silly_count);
207         spin_lock(&dir->i_lock);
208         while (!hlist_empty(&nfsi->silly_list)) {
209                 if (!atomic_inc_not_zero(&nfsi->silly_count))
210                         break;
211                 data = hlist_entry(nfsi->silly_list.first, struct nfs_unlinkdata, list);
212                 hlist_del(&data->list);
213                 spin_unlock(&dir->i_lock);
214                 if (nfs_do_call_unlink(dentry, dir, data) == 0)
215                         nfs_free_unlinkdata(data);
216                 spin_lock(&dir->i_lock);
217         }
218         spin_unlock(&dir->i_lock);
219 }
220
221 /**
222  * nfs_async_unlink - asynchronous unlinking of a file
223  * @dir: parent directory of dentry
224  * @dentry: dentry to unlink
225  */
226 int
227 nfs_async_unlink(struct inode *dir, struct dentry *dentry)
228 {
229         struct nfs_unlinkdata *data;
230         int status = -ENOMEM;
231
232         data = kzalloc(sizeof(*data), GFP_KERNEL);
233         if (data == NULL)
234                 goto out;
235
236         data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
237         if (IS_ERR(data->cred)) {
238                 status = PTR_ERR(data->cred);
239                 goto out_free;
240         }
241
242         status = -EBUSY;
243         spin_lock(&dentry->d_lock);
244         if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
245                 goto out_unlock;
246         dentry->d_flags |= DCACHE_NFSFS_RENAMED;
247         dentry->d_fsdata = data;
248         spin_unlock(&dentry->d_lock);
249         return 0;
250 out_unlock:
251         spin_unlock(&dentry->d_lock);
252         put_rpccred(data->cred);
253 out_free:
254         kfree(data);
255 out:
256         return status;
257 }
258
259 /**
260  * nfs_complete_unlink - Initialize completion of the sillydelete
261  * @dentry: dentry to delete
262  * @inode: inode
263  *
264  * Since we're most likely to be called by dentry_iput(), we
265  * only use the dentry to find the sillydelete. We then copy the name
266  * into the qstr.
267  */
268 void
269 nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
270 {
271         struct nfs_unlinkdata   *data = NULL;
272
273         spin_lock(&dentry->d_lock);
274         if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
275                 dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
276                 data = dentry->d_fsdata;
277         }
278         spin_unlock(&dentry->d_lock);
279
280         if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
281                 nfs_free_unlinkdata(data);
282 }