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