blob: 045ab805c17f5aa25e0a1b5179c3eefd3ba5858a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/fs/nfs/unlink.c
3 *
4 * nfs sillydelete handling
5 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 */
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
15
16struct nfs_unlinkdata {
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040017 struct nfs_removeargs args;
18 struct nfs_removeres res;
19 struct inode *dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 struct rpc_cred *cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -070021};
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023/**
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040024 * nfs_free_unlinkdata - release data from a sillydelete operation.
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 * @data: pointer to unlink structure.
26 */
27static void
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040028nfs_free_unlinkdata(struct nfs_unlinkdata *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070029{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040030 iput(data->dir);
31 put_rpccred(data->cred);
32 kfree(data->args.name.name);
33 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070034}
35
36#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
37/**
38 * nfs_copy_dname - copy dentry name to data structure
39 * @dentry: pointer to dentry
40 * @data: nfs_unlinkdata
41 */
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040042static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070043{
44 char *str;
45 int len = dentry->d_name.len;
46
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040047 str = kmemdup(dentry->d_name.name, NAME_ALLOC_LEN(len), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 if (!str)
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040049 return -ENOMEM;
50 data->args.name.len = len;
51 data->args.name.name = str;
52 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053}
54
55/**
56 * nfs_async_unlink_init - Initialize the RPC info
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040057 * task: rpc_task of the sillydelete
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 */
Trond Myklebust4ce70ad2006-01-03 09:55:05 +010059static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040061 struct nfs_unlinkdata *data = calldata;
62 struct inode *dir = data->dir;
63 struct rpc_message msg = {
64 .rpc_argp = &data->args,
65 .rpc_resp = &data->res,
66 .rpc_cred = data->cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040069 nfs_begin_data_update(dir);
70 NFS_PROTO(dir)->unlink_setup(&msg, dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 rpc_call_setup(task, &msg, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
73
74/**
75 * nfs_async_unlink_done - Sillydelete post-processing
76 * @task: rpc_task of the sillydelete
77 *
78 * Do the directory attribute update.
79 */
Trond Myklebust963d8fe2006-01-03 09:55:04 +010080static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -070081{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040082 struct nfs_unlinkdata *data = calldata;
83 struct inode *dir = data->dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040085 if (!NFS_PROTO(dir)->unlink_done(task, dir))
86 rpc_restart_call(task);
87 else
88 nfs_end_data_update(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089}
90
91/**
92 * nfs_async_unlink_release - Release the sillydelete data.
93 * @task: rpc_task of the sillydelete
94 *
95 * We need to call nfs_put_unlinkdata as a 'tk_release' task since the
96 * rpc_task would be freed too.
97 */
Trond Myklebust963d8fe2006-01-03 09:55:04 +010098static void nfs_async_unlink_release(void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099{
Trond Myklebust963d8fe2006-01-03 09:55:04 +0100100 struct nfs_unlinkdata *data = calldata;
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400101 nfs_free_unlinkdata(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102}
103
Trond Myklebust963d8fe2006-01-03 09:55:04 +0100104static const struct rpc_call_ops nfs_unlink_ops = {
Trond Myklebust4ce70ad2006-01-03 09:55:05 +0100105 .rpc_call_prepare = nfs_async_unlink_init,
Trond Myklebust963d8fe2006-01-03 09:55:04 +0100106 .rpc_call_done = nfs_async_unlink_done,
107 .rpc_release = nfs_async_unlink_release,
108};
109
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400110static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
111{
112 struct rpc_task *task;
113 struct dentry *parent;
114 struct inode *dir;
115
116 if (nfs_copy_dname(dentry, data) < 0)
117 goto out_free;
118
119 parent = dget_parent(dentry);
120 if (parent == NULL)
121 goto out_free;
122 dir = igrab(parent->d_inode);
123 dput(parent);
124 if (dir == NULL)
125 goto out_free;
126
127 data->dir = dir;
128 data->args.fh = NFS_FH(dir);
129 nfs_fattr_init(&data->res.dir_attr);
130
131 task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data);
132 if (!IS_ERR(task))
133 rpc_put_task(task);
134 return 1;
135out_free:
136 return 0;
137}
138
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139/**
140 * nfs_async_unlink - asynchronous unlinking of a file
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400141 * @dir: parent directory of dentry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 * @dentry: dentry to unlink
143 */
144int
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400145nfs_async_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400147 struct nfs_unlinkdata *data;
148 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Eric Sesterhennbd647542006-03-20 13:44:10 -0500150 data = kzalloc(sizeof(*data), GFP_KERNEL);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400151 if (data == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400154 data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 if (IS_ERR(data->cred)) {
156 status = PTR_ERR(data->cred);
157 goto out_free;
158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400160 status = -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 spin_lock(&dentry->d_lock);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400162 if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
163 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 dentry->d_flags |= DCACHE_NFSFS_RENAMED;
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400165 dentry->d_fsdata = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 spin_unlock(&dentry->d_lock);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400167 return 0;
168out_unlock:
169 spin_unlock(&dentry->d_lock);
170 put_rpccred(data->cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171out_free:
172 kfree(data);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400173out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 return status;
175}
176
177/**
178 * nfs_complete_unlink - Initialize completion of the sillydelete
179 * @dentry: dentry to delete
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400180 * @inode: inode
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 *
182 * Since we're most likely to be called by dentry_iput(), we
183 * only use the dentry to find the sillydelete. We then copy the name
184 * into the qstr.
185 */
186void
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400187nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400189 struct nfs_unlinkdata *data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 spin_lock(&dentry->d_lock);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400192 if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
193 dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
194 data = dentry->d_fsdata;
195 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 spin_unlock(&dentry->d_lock);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400197
198 if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
199 nfs_free_unlinkdata(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200}