Blame view

fs/nfs/unlink.c 4.44 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   *  linux/fs/nfs/unlink.c
   *
   * nfs sillydelete handling
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
14
15
16
   */
  
  #include <linux/slab.h>
  #include <linux/string.h>
  #include <linux/dcache.h>
  #include <linux/sunrpc/sched.h>
  #include <linux/sunrpc/clnt.h>
  #include <linux/nfs_fs.h>
  
  
  struct nfs_unlinkdata {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
17
18
19
  	struct nfs_removeargs args;
  	struct nfs_removeres res;
  	struct inode *dir;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  	struct rpc_cred	*cred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  /**
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
23
   * nfs_free_unlinkdata - release data from a sillydelete operation.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
   * @data: pointer to unlink structure.
   */
  static void
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
27
  nfs_free_unlinkdata(struct nfs_unlinkdata *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
29
30
31
32
  	iput(data->dir);
  	put_rpccred(data->cred);
  	kfree(data->args.name.name);
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
36
37
38
39
40
  }
  
  #define NAME_ALLOC_LEN(len)	((len+16) & ~15)
  /**
   * nfs_copy_dname - copy dentry name to data structure
   * @dentry: pointer to dentry
   * @data: nfs_unlinkdata
   */
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
41
  static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  {
  	char		*str;
  	int		len = dentry->d_name.len;
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
45
  	str = kmemdup(dentry->d_name.name, NAME_ALLOC_LEN(len), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  	if (!str)
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
47
48
49
50
  		return -ENOMEM;
  	data->args.name.len = len;
  	data->args.name.name = str;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
  }
  
  /**
   * nfs_async_unlink_init - Initialize the RPC info
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
55
   * task: rpc_task of the sillydelete
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
   */
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
57
  static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
59
60
61
62
63
64
  	struct nfs_unlinkdata *data = calldata;
  	struct inode *dir = data->dir;
  	struct rpc_message msg = {
  		.rpc_argp = &data->args,
  		.rpc_resp = &data->res,
  		.rpc_cred = data->cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66

e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
67
68
  	nfs_begin_data_update(dir);
  	NFS_PROTO(dir)->unlink_setup(&msg, dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  	rpc_call_setup(task, &msg, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
75
76
77
  }
  
  /**
   * nfs_async_unlink_done - Sillydelete post-processing
   * @task: rpc_task of the sillydelete
   *
   * Do the directory attribute update.
   */
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
78
  static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
80
81
82
83
84
85
86
  	struct nfs_unlinkdata *data = calldata;
  	struct inode *dir = data->dir;
  
  	if (!NFS_PROTO(dir)->unlink_done(task, dir))
  		rpc_restart_call(task);
  	else
  		nfs_end_data_update(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
92
93
94
95
  }
  
  /**
   * nfs_async_unlink_release - Release the sillydelete data.
   * @task: rpc_task of the sillydelete
   *
   * We need to call nfs_put_unlinkdata as a 'tk_release' task since the
   * rpc_task would be freed too.
   */
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
96
  static void nfs_async_unlink_release(void *calldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
98
  	struct nfs_unlinkdata	*data = calldata;
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
99
  	nfs_free_unlinkdata(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
101
  static const struct rpc_call_ops nfs_unlink_ops = {
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
102
  	.rpc_call_prepare = nfs_async_unlink_init,
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
103
104
105
  	.rpc_call_done = nfs_async_unlink_done,
  	.rpc_release = nfs_async_unlink_release,
  };
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
  {
  	struct rpc_task *task;
  	struct dentry *parent;
  	struct inode *dir;
  
  	if (nfs_copy_dname(dentry, data) < 0)
  		goto out_free;
  
  	parent = dget_parent(dentry);
  	if (parent == NULL)
  		goto out_free;
  	dir = igrab(parent->d_inode);
  	dput(parent);
  	if (dir == NULL)
  		goto out_free;
  
  	data->dir = dir;
  	data->args.fh = NFS_FH(dir);
  	nfs_fattr_init(&data->res.dir_attr);
  
  	task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data);
  	if (!IS_ERR(task))
  		rpc_put_task(task);
  	return 1;
  out_free:
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
  /**
   * nfs_async_unlink - asynchronous unlinking of a file
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
136
   * @dir: parent directory of dentry
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
   * @dentry: dentry to unlink
   */
  int
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
140
  nfs_async_unlink(struct inode *dir, struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
142
143
  	struct nfs_unlinkdata *data;
  	int status = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144

bd6475454   Eric Sesterhenn   NFS: kzalloc conv...
145
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
146
  	if (data == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148

e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
149
  	data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
  	if (IS_ERR(data->cred)) {
  		status = PTR_ERR(data->cred);
  		goto out_free;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154

e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
155
  	status = -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  	spin_lock(&dentry->d_lock);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
157
158
  	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
160
  	dentry->d_fsdata = data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  	spin_unlock(&dentry->d_lock);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
162
163
164
165
  	return 0;
  out_unlock:
  	spin_unlock(&dentry->d_lock);
  	put_rpccred(data->cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
  out_free:
  	kfree(data);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
168
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
  	return status;
  }
  
  /**
   * nfs_complete_unlink - Initialize completion of the sillydelete
   * @dentry: dentry to delete
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
175
   * @inode: inode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
180
181
   *
   * Since we're most likely to be called by dentry_iput(), we
   * only use the dentry to find the sillydelete. We then copy the name
   * into the qstr.
   */
  void
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
182
  nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
184
  	struct nfs_unlinkdata	*data = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  	spin_lock(&dentry->d_lock);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
187
188
189
190
  	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
  		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
  		data = dentry->d_fsdata;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  	spin_unlock(&dentry->d_lock);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
192
193
194
  
  	if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
  		nfs_free_unlinkdata(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  }