blob: 1aed850d18f2ebab29f2b6b7077f4effb85413ff [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_PROTO(dir)->unlink_setup(&msg, dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 rpc_call_setup(task, &msg, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071}
72
73/**
74 * nfs_async_unlink_done - Sillydelete post-processing
75 * @task: rpc_task of the sillydelete
76 *
77 * Do the directory attribute update.
78 */
Trond Myklebust963d8fe2006-01-03 09:55:04 +010079static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -070080{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040081 struct nfs_unlinkdata *data = calldata;
82 struct inode *dir = data->dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040084 if (!NFS_PROTO(dir)->unlink_done(task, dir))
85 rpc_restart_call(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086}
87
88/**
89 * nfs_async_unlink_release - Release the sillydelete data.
90 * @task: rpc_task of the sillydelete
91 *
92 * We need to call nfs_put_unlinkdata as a 'tk_release' task since the
93 * rpc_task would be freed too.
94 */
Trond Myklebust963d8fe2006-01-03 09:55:04 +010095static void nfs_async_unlink_release(void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
Trond Myklebust963d8fe2006-01-03 09:55:04 +010097 struct nfs_unlinkdata *data = calldata;
Trond Myklebuste4eff1a2007-07-14 15:39:58 -040098 nfs_free_unlinkdata(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099}
100
Trond Myklebust963d8fe2006-01-03 09:55:04 +0100101static const struct rpc_call_ops nfs_unlink_ops = {
Trond Myklebust4ce70ad2006-01-03 09:55:05 +0100102 .rpc_call_prepare = nfs_async_unlink_init,
Trond Myklebust963d8fe2006-01-03 09:55:04 +0100103 .rpc_call_done = nfs_async_unlink_done,
104 .rpc_release = nfs_async_unlink_release,
105};
106
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400107static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
108{
109 struct rpc_task *task;
110 struct dentry *parent;
111 struct inode *dir;
112
113 if (nfs_copy_dname(dentry, data) < 0)
114 goto out_free;
115
116 parent = dget_parent(dentry);
117 if (parent == NULL)
118 goto out_free;
119 dir = igrab(parent->d_inode);
120 dput(parent);
121 if (dir == NULL)
122 goto out_free;
123
124 data->dir = dir;
125 data->args.fh = NFS_FH(dir);
126 nfs_fattr_init(&data->res.dir_attr);
127
128 task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data);
129 if (!IS_ERR(task))
130 rpc_put_task(task);
131 return 1;
132out_free:
133 return 0;
134}
135
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136/**
137 * nfs_async_unlink - asynchronous unlinking of a file
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400138 * @dir: parent directory of dentry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 * @dentry: dentry to unlink
140 */
141int
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400142nfs_async_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400144 struct nfs_unlinkdata *data;
145 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Eric Sesterhennbd647542006-03-20 13:44:10 -0500147 data = kzalloc(sizeof(*data), GFP_KERNEL);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400148 if (data == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400151 data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 if (IS_ERR(data->cred)) {
153 status = PTR_ERR(data->cred);
154 goto out_free;
155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400157 status = -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 spin_lock(&dentry->d_lock);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400159 if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
160 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 dentry->d_flags |= DCACHE_NFSFS_RENAMED;
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400162 dentry->d_fsdata = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 spin_unlock(&dentry->d_lock);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400164 return 0;
165out_unlock:
166 spin_unlock(&dentry->d_lock);
167 put_rpccred(data->cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168out_free:
169 kfree(data);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400170out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 return status;
172}
173
174/**
175 * nfs_complete_unlink - Initialize completion of the sillydelete
176 * @dentry: dentry to delete
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400177 * @inode: inode
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 *
179 * Since we're most likely to be called by dentry_iput(), we
180 * only use the dentry to find the sillydelete. We then copy the name
181 * into the qstr.
182 */
183void
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400184nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400186 struct nfs_unlinkdata *data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 spin_lock(&dentry->d_lock);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400189 if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
190 dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
191 data = dentry->d_fsdata;
192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 spin_unlock(&dentry->d_lock);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -0400194
195 if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
196 nfs_free_unlinkdata(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}