Blame view

fs/nfs/proc.c 18.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  /*
   *  linux/fs/nfs/proc.c
   *
   *  Copyright (C) 1992, 1993, 1994  Rick Sladkey
   *
   *  OS-independent nfs remote procedure call functions
   *
   *  Tuned by Alan Cox <A.Cox@swansea.ac.uk> for >3K buffers
   *  so at last we can have decent(ish) throughput off a 
   *  Sun server.
   *
   *  Coding optimized and cleaned up by Florian La Roche.
   *  Note: Error returns are optimized for NFS_OK, which isn't translated via
   *  nfs_stat_to_errno(), but happens to be already the right return code.
   *
   *  Also, the code currently doesn't check the size of the packet, when
   *  it decodes the packet.
   *
   *  Feel free to fix it and mail me the diffs if it worries you.
   *
   *  Completely rewritten to support the new RPC call interface;
   *  rewrote and moved the entire XDR stuff to xdr.c
   *  --Olaf Kirch June 1996
   *
   *  The code below initializes all auto variables explicitly, otherwise
   *  it will fail to work as a module (gcc generates a memset call for an
   *  incomplete struct).
   */
  
  #include <linux/types.h>
  #include <linux/param.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  #include <linux/time.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
41
42
43
  #include <linux/errno.h>
  #include <linux/string.h>
  #include <linux/in.h>
  #include <linux/pagemap.h>
  #include <linux/sunrpc/clnt.h>
  #include <linux/nfs.h>
  #include <linux/nfs2.h>
  #include <linux/nfs_fs.h>
  #include <linux/nfs_page.h>
  #include <linux/lockd/bind.h>
d310310cb   Jeff Layton   Freezer / sunrpc ...
44
  #include <linux/freezer.h>
f7b422b17   David Howells   NFS: Split fs/nfs...
45
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  
  #define NFSDBG_FACILITY		NFSDBG_PROC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  /*
97cefcc6d   Jeff Layton   nfs: handle NFSv2...
49
50
51
52
53
54
55
56
57
58
59
60
61
   * wrapper to handle the -EKEYEXPIRED error message. This should generally
   * only happen if using krb5 auth and a user's TGT expires. NFSv2 doesn't
   * support the NFSERR_JUKEBOX error code, but we handle this situation in the
   * same way that we handle that error with NFSv3.
   */
  static int
  nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
  {
  	int res;
  	do {
  		res = rpc_call_sync(clnt, msg, flags);
  		if (res != -EKEYEXPIRED)
  			break;
d310310cb   Jeff Layton   Freezer / sunrpc ...
62
  		freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
97cefcc6d   Jeff Layton   nfs: handle NFSv2...
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  		res = -ERESTARTSYS;
  	} while (!fatal_signal_pending(current));
  	return res;
  }
  
  #define rpc_call_sync(clnt, msg, flags)	nfs_rpc_wrapper(clnt, msg, flags)
  
  static int
  nfs_async_handle_expired_key(struct rpc_task *task)
  {
  	if (task->tk_status != -EKEYEXPIRED)
  		return 0;
  	task->tk_status = 0;
  	rpc_restart_call(task);
  	rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
  	return 1;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
85
86
87
88
89
   * Bare-bones access to getattr: this is for nfs_read_super.
   */
  static int
  nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
  		  struct nfs_fsinfo *info)
  {
  	struct nfs_fattr *fattr = info->fattr;
  	struct nfs2_fsstat fsinfo;
dead28da8   Chuck Lever   SUNRPC: eliminate...
90
91
92
93
94
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_GETATTR],
  		.rpc_argp	= fhandle,
  		.rpc_resp	= fattr,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  	int status;
3110ff804   Harvey Harrison   nfs: replace rema...
96
97
  	dprintk("%s: call getattr
  ", __func__);
0e574af1b   Trond Myklebust   NFS: Cleanup init...
98
  	nfs_fattr_init(fattr);
37ca8f5c6   EG Keizer   nfs: authenticate...
99
100
101
102
  	status = rpc_call_sync(server->client, &msg, 0);
  	/* Retry with default authentication if different */
  	if (status && server->nfs_client->cl_rpcclient != server->client)
  		status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
3110ff804   Harvey Harrison   nfs: replace rema...
103
104
  	dprintk("%s: reply getattr: %d
  ", __func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
  	if (status)
  		return status;
3110ff804   Harvey Harrison   nfs: replace rema...
107
108
  	dprintk("%s: call statfs
  ", __func__);
dead28da8   Chuck Lever   SUNRPC: eliminate...
109
110
  	msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS];
  	msg.rpc_resp = &fsinfo;
37ca8f5c6   EG Keizer   nfs: authenticate...
111
112
113
114
  	status = rpc_call_sync(server->client, &msg, 0);
  	/* Retry with default authentication if different */
  	if (status && server->nfs_client->cl_rpcclient != server->client)
  		status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
3110ff804   Harvey Harrison   nfs: replace rema...
115
116
  	dprintk("%s: reply statfs: %d
  ", __func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  	if (status)
  		return status;
  	info->rtmax  = NFS_MAXDATA;
  	info->rtpref = fsinfo.tsize;
  	info->rtmult = fsinfo.bsize;
  	info->wtmax  = NFS_MAXDATA;
  	info->wtpref = fsinfo.tsize;
  	info->wtmult = fsinfo.bsize;
  	info->dtpref = fsinfo.tsize;
  	info->maxfilesize = 0x7FFFFFFF;
  	info->lease_time = 0;
  	return 0;
  }
  
  /*
   * One function for each procedure in the NFS protocol.
   */
  static int
  nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
  		struct nfs_fattr *fattr)
  {
dead28da8   Chuck Lever   SUNRPC: eliminate...
138
139
140
141
142
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_GETATTR],
  		.rpc_argp	= fhandle,
  		.rpc_resp	= fattr,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
  	int	status;
  
  	dprintk("NFS call  getattr
  ");
0e574af1b   Trond Myklebust   NFS: Cleanup init...
147
  	nfs_fattr_init(fattr);
dead28da8   Chuck Lever   SUNRPC: eliminate...
148
  	status = rpc_call_sync(server->client, &msg, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  	dprintk("NFS reply getattr: %d
  ", status);
  	return status;
  }
  
  static int
  nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
  		 struct iattr *sattr)
  {
  	struct inode *inode = dentry->d_inode;
  	struct nfs_sattrargs	arg = { 
  		.fh	= NFS_FH(inode),
  		.sattr	= sattr
  	};
dead28da8   Chuck Lever   SUNRPC: eliminate...
163
164
165
166
167
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_SETATTR],
  		.rpc_argp	= &arg,
  		.rpc_resp	= fattr,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  	int	status;
cf3fff54a   Trond Myklebust   NFS: Send valid m...
169
170
  	/* Mask out the non-modebit related stuff from attr->ia_mode */
  	sattr->ia_mode &= S_IALLUGO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
  	dprintk("NFS call  setattr
  ");
659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
173
174
  	if (sattr->ia_valid & ATTR_FILE)
  		msg.rpc_cred = nfs_file_cred(sattr->ia_file);
0e574af1b   Trond Myklebust   NFS: Cleanup init...
175
  	nfs_fattr_init(fattr);
dead28da8   Chuck Lever   SUNRPC: eliminate...
176
  	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
65e4308d2   Trond Myklebust   [PATCH] NFS: Ensu...
177
178
  	if (status == 0)
  		nfs_setattr_update_inode(inode, sattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
  	dprintk("NFS reply setattr: %d
  ", status);
  	return status;
  }
  
  static int
7c5130588   Bryan Schumaker   NFS: lookup suppo...
185
  nfs_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
189
190
191
192
193
194
195
196
  		struct nfs_fh *fhandle, struct nfs_fattr *fattr)
  {
  	struct nfs_diropargs	arg = {
  		.fh		= NFS_FH(dir),
  		.name		= name->name,
  		.len		= name->len
  	};
  	struct nfs_diropok	res = {
  		.fh		= fhandle,
  		.fattr		= fattr
  	};
dead28da8   Chuck Lever   SUNRPC: eliminate...
197
198
199
200
201
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_LOOKUP],
  		.rpc_argp	= &arg,
  		.rpc_resp	= &res,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
  	int			status;
  
  	dprintk("NFS call  lookup %s
  ", name->name);
0e574af1b   Trond Myklebust   NFS: Cleanup init...
206
  	nfs_fattr_init(fattr);
dead28da8   Chuck Lever   SUNRPC: eliminate...
207
  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  	dprintk("NFS reply lookup: %d
  ", status);
  	return status;
  }
  
  static int nfs_proc_readlink(struct inode *inode, struct page *page,
  		unsigned int pgbase, unsigned int pglen)
  {
  	struct nfs_readlinkargs	args = {
  		.fh		= NFS_FH(inode),
  		.pgbase		= pgbase,
  		.pglen		= pglen,
  		.pages		= &page
  	};
dead28da8   Chuck Lever   SUNRPC: eliminate...
222
223
224
225
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_READLINK],
  		.rpc_argp	= &args,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
  	int			status;
  
  	dprintk("NFS call  readlink
  ");
dead28da8   Chuck Lever   SUNRPC: eliminate...
230
  	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
234
  	dprintk("NFS reply readlink: %d
  ", status);
  	return status;
  }
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  struct nfs_createdata {
  	struct nfs_createargs arg;
  	struct nfs_diropok res;
  	struct nfs_fh fhandle;
  	struct nfs_fattr fattr;
  };
  
  static struct nfs_createdata *nfs_alloc_createdata(struct inode *dir,
  		struct dentry *dentry, struct iattr *sattr)
  {
  	struct nfs_createdata *data;
  
  	data = kmalloc(sizeof(*data), GFP_KERNEL);
  
  	if (data != NULL) {
  		data->arg.fh = NFS_FH(dir);
  		data->arg.name = dentry->d_name.name;
  		data->arg.len = dentry->d_name.len;
  		data->arg.sattr = sattr;
  		nfs_fattr_init(&data->fattr);
  		data->fhandle.size = 0;
  		data->res.fh = &data->fhandle;
  		data->res.fattr = &data->fattr;
  	}
  	return data;
  };
  
  static void nfs_free_createdata(const struct nfs_createdata *data)
  {
  	kfree(data);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
  static int
  nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
c0204fd2b   Trond Myklebust   NFS: Clean up nfs...
268
  		int flags, struct nfs_open_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  {
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
270
  	struct nfs_createdata *data;
dead28da8   Chuck Lever   SUNRPC: eliminate...
271
272
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_CREATE],
dead28da8   Chuck Lever   SUNRPC: eliminate...
273
  	};
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
274
  	int status = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
  	dprintk("NFS call  create %s
  ", dentry->d_name.name);
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
278
279
280
281
282
  	data = nfs_alloc_createdata(dir, dentry, sattr);
  	if (data == NULL)
  		goto out;
  	msg.rpc_argp = &data->arg;
  	msg.rpc_resp = &data->res;
dead28da8   Chuck Lever   SUNRPC: eliminate...
283
  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
bad2a5241   Trond Myklebust   NFSv2: Ensure tha...
284
  	nfs_mark_for_revalidate(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	if (status == 0)
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
286
287
288
  		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
  	nfs_free_createdata(data);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
295
296
297
298
299
300
  	dprintk("NFS reply create: %d
  ", status);
  	return status;
  }
  
  /*
   * In NFSv2, mknod is grafted onto the create call.
   */
  static int
  nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
  	       dev_t rdev)
  {
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
301
  	struct nfs_createdata *data;
dead28da8   Chuck Lever   SUNRPC: eliminate...
302
303
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_CREATE],
dead28da8   Chuck Lever   SUNRPC: eliminate...
304
  	};
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
305
306
  	umode_t mode;
  	int status = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
313
314
315
316
317
318
  
  	dprintk("NFS call  mknod %s
  ", dentry->d_name.name);
  
  	mode = sattr->ia_mode;
  	if (S_ISFIFO(mode)) {
  		sattr->ia_mode = (mode & ~S_IFMT) | S_IFCHR;
  		sattr->ia_valid &= ~ATTR_SIZE;
  	} else if (S_ISCHR(mode) || S_ISBLK(mode)) {
  		sattr->ia_valid |= ATTR_SIZE;
  		sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */
  	}
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
319
320
321
322
323
  	data = nfs_alloc_createdata(dir, dentry, sattr);
  	if (data == NULL)
  		goto out;
  	msg.rpc_argp = &data->arg;
  	msg.rpc_resp = &data->res;
dead28da8   Chuck Lever   SUNRPC: eliminate...
324
  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
decf491f3   Trond Myklebust   NFS: Don't let nf...
325
  	nfs_mark_for_revalidate(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
  
  	if (status == -EINVAL && S_ISFIFO(mode)) {
  		sattr->ia_mode = mode;
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
329
  		nfs_fattr_init(data->res.fattr);
dead28da8   Chuck Lever   SUNRPC: eliminate...
330
  		status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
  	}
  	if (status == 0)
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
333
334
335
  		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
  	nfs_free_createdata(data);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
341
342
343
  	dprintk("NFS reply mknod: %d
  ", status);
  	return status;
  }
    
  static int
  nfs_proc_remove(struct inode *dir, struct qstr *name)
  {
4fdc17b2a   Trond Myklebust   NFS: Introduce st...
344
345
346
347
  	struct nfs_removeargs arg = {
  		.fh = NFS_FH(dir),
  		.name.len = name->len,
  		.name.name = name->name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
  	};
4fdc17b2a   Trond Myklebust   NFS: Introduce st...
349
350
351
  	struct rpc_message msg = { 
  		.rpc_proc = &nfs_procedures[NFSPROC_REMOVE],
  		.rpc_argp = &arg,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
357
  	};
  	int			status;
  
  	dprintk("NFS call  remove %s
  ", name->name);
  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
decf491f3   Trond Myklebust   NFS: Don't let nf...
358
  	nfs_mark_for_revalidate(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
363
  
  	dprintk("NFS reply remove: %d
  ", status);
  	return status;
  }
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
364
365
  static void
  nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  	msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  }
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
369
  static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  {
97cefcc6d   Jeff Layton   nfs: handle NFSv2...
371
372
  	if (nfs_async_handle_expired_key(task))
  		return 0;
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
373
374
  	nfs_mark_for_revalidate(dir);
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  }
d3d4152a5   Jeff Layton   nfs: make sillyre...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  static void
  nfs_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
  {
  	msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME];
  }
  
  static int
  nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
  		     struct inode *new_dir)
  {
  	if (nfs_async_handle_expired_key(task))
  		return 0;
  	nfs_mark_for_revalidate(old_dir);
  	nfs_mark_for_revalidate(new_dir);
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
  static int
  nfs_proc_rename(struct inode *old_dir, struct qstr *old_name,
  		struct inode *new_dir, struct qstr *new_name)
  {
  	struct nfs_renameargs	arg = {
920769f03   Jeff Layton   nfs: standardize ...
397
398
399
400
  		.old_dir	= NFS_FH(old_dir),
  		.old_name	= old_name,
  		.new_dir	= NFS_FH(new_dir),
  		.new_name	= new_name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  	};
dead28da8   Chuck Lever   SUNRPC: eliminate...
402
403
404
405
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_RENAME],
  		.rpc_argp	= &arg,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
  	int			status;
  
  	dprintk("NFS call  rename %s -> %s
  ", old_name->name, new_name->name);
dead28da8   Chuck Lever   SUNRPC: eliminate...
410
  	status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
decf491f3   Trond Myklebust   NFS: Don't let nf...
411
412
  	nfs_mark_for_revalidate(old_dir);
  	nfs_mark_for_revalidate(new_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  	dprintk("NFS reply rename: %d
  ", status);
  	return status;
  }
  
  static int
  nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
  {
  	struct nfs_linkargs	arg = {
  		.fromfh		= NFS_FH(inode),
  		.tofh		= NFS_FH(dir),
  		.toname		= name->name,
  		.tolen		= name->len
  	};
dead28da8   Chuck Lever   SUNRPC: eliminate...
427
428
429
430
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_LINK],
  		.rpc_argp	= &arg,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
433
434
  	int			status;
  
  	dprintk("NFS call  link %s
  ", name->name);
dead28da8   Chuck Lever   SUNRPC: eliminate...
435
  	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
5ba7cc480   Trond Myklebust   NFS: Fix post-op ...
436
  	nfs_mark_for_revalidate(inode);
decf491f3   Trond Myklebust   NFS: Don't let nf...
437
  	nfs_mark_for_revalidate(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
440
441
442
443
  	dprintk("NFS reply link: %d
  ", status);
  	return status;
  }
  
  static int
94a6d7532   Chuck Lever   NFS: Use cached p...
444
445
  nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
  		 unsigned int len, struct iattr *sattr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  {
23a306120   Trond Myklebust   NFS: Reduce the s...
447
448
  	struct nfs_fh *fh;
  	struct nfs_fattr *fattr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
  	struct nfs_symlinkargs	arg = {
  		.fromfh		= NFS_FH(dir),
4f390c152   Chuck Lever   NFS: Fix double d...
451
452
  		.fromname	= dentry->d_name.name,
  		.fromlen	= dentry->d_name.len,
94a6d7532   Chuck Lever   NFS: Use cached p...
453
454
  		.pages		= &page,
  		.pathlen	= len,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
  		.sattr		= sattr
  	};
dead28da8   Chuck Lever   SUNRPC: eliminate...
457
458
459
460
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_SYMLINK],
  		.rpc_argp	= &arg,
  	};
23a306120   Trond Myklebust   NFS: Reduce the s...
461
462
463
464
  	int status = -ENAMETOOLONG;
  
  	dprintk("NFS call  symlink %s
  ", dentry->d_name.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465

94a6d7532   Chuck Lever   NFS: Use cached p...
466
  	if (len > NFS2_MAXPATHLEN)
23a306120   Trond Myklebust   NFS: Reduce the s...
467
  		goto out;
4f390c152   Chuck Lever   NFS: Fix double d...
468

23a306120   Trond Myklebust   NFS: Reduce the s...
469
470
471
472
  	fh = nfs_alloc_fhandle();
  	fattr = nfs_alloc_fattr();
  	status = -ENOMEM;
  	if (fh == NULL || fattr == NULL)
878215feb   Jesper Juhl   NFS: Don't leak i...
473
  		goto out_free;
94a6d7532   Chuck Lever   NFS: Use cached p...
474

dead28da8   Chuck Lever   SUNRPC: eliminate...
475
  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
decf491f3   Trond Myklebust   NFS: Don't let nf...
476
  	nfs_mark_for_revalidate(dir);
4f390c152   Chuck Lever   NFS: Fix double d...
477
478
479
480
481
482
  
  	/*
  	 * V2 SYMLINK requests don't return any attributes.  Setting the
  	 * filehandle size to zero indicates to nfs_instantiate that it
  	 * should fill in the data with a LOOKUP call on the wire.
  	 */
23a306120   Trond Myklebust   NFS: Reduce the s...
483
484
  	if (status == 0)
  		status = nfs_instantiate(dentry, fh, fattr);
4f390c152   Chuck Lever   NFS: Fix double d...
485

878215feb   Jesper Juhl   NFS: Don't leak i...
486
  out_free:
23a306120   Trond Myklebust   NFS: Reduce the s...
487
488
489
  	nfs_free_fattr(fattr);
  	nfs_free_fhandle(fh);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
493
494
495
496
497
  	dprintk("NFS reply symlink: %d
  ", status);
  	return status;
  }
  
  static int
  nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
  {
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
498
  	struct nfs_createdata *data;
dead28da8   Chuck Lever   SUNRPC: eliminate...
499
500
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_MKDIR],
dead28da8   Chuck Lever   SUNRPC: eliminate...
501
  	};
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
502
  	int status = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
  
  	dprintk("NFS call  mkdir %s
  ", dentry->d_name.name);
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
506
507
508
509
510
  	data = nfs_alloc_createdata(dir, dentry, sattr);
  	if (data == NULL)
  		goto out;
  	msg.rpc_argp = &data->arg;
  	msg.rpc_resp = &data->res;
dead28da8   Chuck Lever   SUNRPC: eliminate...
511
  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
decf491f3   Trond Myklebust   NFS: Don't let nf...
512
  	nfs_mark_for_revalidate(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  	if (status == 0)
eb872f0c8   Trond Myklebust   NFS: Reduce the s...
514
515
516
  		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
  	nfs_free_createdata(data);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
520
521
522
523
524
525
526
527
528
529
  	dprintk("NFS reply mkdir: %d
  ", status);
  	return status;
  }
  
  static int
  nfs_proc_rmdir(struct inode *dir, struct qstr *name)
  {
  	struct nfs_diropargs	arg = {
  		.fh		= NFS_FH(dir),
  		.name		= name->name,
  		.len		= name->len
  	};
dead28da8   Chuck Lever   SUNRPC: eliminate...
530
531
532
533
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_RMDIR],
  		.rpc_argp	= &arg,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
537
  	int			status;
  
  	dprintk("NFS call  rmdir %s
  ", name->name);
dead28da8   Chuck Lever   SUNRPC: eliminate...
538
  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
decf491f3   Trond Myklebust   NFS: Don't let nf...
539
  	nfs_mark_for_revalidate(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
544
545
546
547
548
549
550
551
552
553
  	dprintk("NFS reply rmdir: %d
  ", status);
  	return status;
  }
  
  /*
   * The READDIR implementation is somewhat hackish - we pass a temporary
   * buffer to the encode function, which installs it in the receive
   * the receive iovec. The decode function just parses the reply to make
   * sure it is syntactically correct; the entries itself are decoded
   * from nfs_readdir by calling the decode_entry function directly.
   */
  static int
  nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
56e4ebf87   Bryan Schumaker   NFS: readdir with...
554
  		 u64 cookie, struct page **pages, unsigned int count, int plus)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
558
559
560
  {
  	struct inode		*dir = dentry->d_inode;
  	struct nfs_readdirargs	arg = {
  		.fh		= NFS_FH(dir),
  		.cookie		= cookie,
  		.count		= count,
56e4ebf87   Bryan Schumaker   NFS: readdir with...
561
  		.pages		= pages,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
565
  	};
  	struct rpc_message	msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_READDIR],
  		.rpc_argp	= &arg,
dead28da8   Chuck Lever   SUNRPC: eliminate...
566
  		.rpc_cred	= cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
  	};
  	int			status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
571
  	dprintk("NFS call  readdir %d
  ", (unsigned int)cookie);
  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
c48129983   Trond Myklebust   NFS: Fix atime re...
572
  	nfs_invalidate_atime(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
  	dprintk("NFS reply readdir: %d
  ", status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
580
581
582
  	return status;
  }
  
  static int
  nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
  			struct nfs_fsstat *stat)
  {
  	struct nfs2_fsstat fsinfo;
dead28da8   Chuck Lever   SUNRPC: eliminate...
583
584
585
586
587
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_STATFS],
  		.rpc_argp	= fhandle,
  		.rpc_resp	= &fsinfo,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
591
  	int	status;
  
  	dprintk("NFS call  statfs
  ");
0e574af1b   Trond Myklebust   NFS: Cleanup init...
592
  	nfs_fattr_init(stat->fattr);
dead28da8   Chuck Lever   SUNRPC: eliminate...
593
  	status = rpc_call_sync(server->client, &msg, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  	dprintk("NFS reply statfs: %d
  ", status);
  	if (status)
  		goto out;
  	stat->tbytes = (u64)fsinfo.blocks * fsinfo.bsize;
  	stat->fbytes = (u64)fsinfo.bfree  * fsinfo.bsize;
  	stat->abytes = (u64)fsinfo.bavail * fsinfo.bsize;
  	stat->tfiles = 0;
  	stat->ffiles = 0;
  	stat->afiles = 0;
  out:
  	return status;
  }
  
  static int
  nfs_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
  			struct nfs_fsinfo *info)
  {
  	struct nfs2_fsstat fsinfo;
dead28da8   Chuck Lever   SUNRPC: eliminate...
613
614
615
616
617
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs_procedures[NFSPROC_STATFS],
  		.rpc_argp	= fhandle,
  		.rpc_resp	= &fsinfo,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
620
621
  	int	status;
  
  	dprintk("NFS call  fsinfo
  ");
0e574af1b   Trond Myklebust   NFS: Cleanup init...
622
  	nfs_fattr_init(info->fattr);
dead28da8   Chuck Lever   SUNRPC: eliminate...
623
  	status = rpc_call_sync(server->client, &msg, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
  	dprintk("NFS reply fsinfo: %d
  ", status);
  	if (status)
  		goto out;
  	info->rtmax  = NFS_MAXDATA;
  	info->rtpref = fsinfo.tsize;
  	info->rtmult = fsinfo.bsize;
  	info->wtmax  = NFS_MAXDATA;
  	info->wtpref = fsinfo.tsize;
  	info->wtmult = fsinfo.bsize;
  	info->dtpref = fsinfo.tsize;
  	info->maxfilesize = 0x7FFFFFFF;
  	info->lease_time = 0;
  out:
  	return status;
  }
  
  static int
  nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
  		  struct nfs_pathconf *info)
  {
  	info->max_link = 0;
  	info->max_namelen = NFS2_MAXNAMLEN;
  	return 0;
  }
ec06c096e   Trond Myklebust   NFS: Cleanup of N...
649
  static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  {
97cefcc6d   Jeff Layton   nfs: handle NFSv2...
651
652
  	if (nfs_async_handle_expired_key(task))
  		return -EAGAIN;
8850df999   Trond Myklebust   NFS: Fix atime re...
653
  	nfs_invalidate_atime(data->inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
658
659
660
661
  	if (task->tk_status >= 0) {
  		nfs_refresh_inode(data->inode, data->res.fattr);
  		/* Emulate the eof flag, which isn't normally needed in NFSv2
  		 * as it is guaranteed to always return the file attributes
  		 */
  		if (data->args.offset + data->args.count >= data->res.fattr->size)
  			data->res.eof = 1;
  	}
ec06c096e   Trond Myklebust   NFS: Cleanup of N...
662
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
  }
bdc7f021f   Trond Myklebust   NFS: Clean up the...
664
  static void nfs_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  {
bdc7f021f   Trond Myklebust   NFS: Clean up the...
666
  	msg->rpc_proc = &nfs_procedures[NFSPROC_READ];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  }
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
668
  static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  {
97cefcc6d   Jeff Layton   nfs: handle NFSv2...
670
671
  	if (nfs_async_handle_expired_key(task))
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
  	if (task->tk_status >= 0)
70ca88521   Trond Myklebust   NFS: Fake up 'wcc...
673
  		nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
674
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
  }
bdc7f021f   Trond Myklebust   NFS: Clean up the...
676
  static void nfs_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
  	/* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */
  	data->args.stable = NFS_FILE_SYNC;
bdc7f021f   Trond Myklebust   NFS: Clean up the...
680
  	msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
  }
  
  static void
bdc7f021f   Trond Myklebust   NFS: Clean up the...
684
  nfs_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
689
690
691
  {
  	BUG();
  }
  
  static int
  nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
  {
1093a60ef   Chuck Lever   NLM/NFS: Use cach...
692
693
694
  	struct inode *inode = filp->f_path.dentry->d_inode;
  
  	return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  }
2116271a3   Trond Myklebust   NFS: Add correct ...
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
  /* Helper functions for NFS lock bounds checking */
  #define NFS_LOCK32_OFFSET_MAX ((__s32)0x7fffffffUL)
  static int nfs_lock_check_bounds(const struct file_lock *fl)
  {
  	__s32 start, end;
  
  	start = (__s32)fl->fl_start;
  	if ((loff_t)start != fl->fl_start)
  		goto out_einval;
  
  	if (fl->fl_end != OFFSET_MAX) {
  		end = (__s32)fl->fl_end;
  		if ((loff_t)end != fl->fl_end)
  			goto out_einval;
  	} else
  		end = NFS_LOCK32_OFFSET_MAX;
  
  	if (start < 0 || start > end)
  		goto out_einval;
  	return 0;
  out_einval:
  	return -EINVAL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719

509de8111   David Howells   NFS: Add extra co...
720
  const struct nfs_rpc_ops nfs_v2_clientops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
  	.version	= 2,		       /* protocol version */
  	.dentry_ops	= &nfs_dentry_operations,
  	.dir_inode_ops	= &nfs_dir_inode_operations,
92cfc62cb   J. Bruce Fields   [PATCH] NFS: Allo...
724
  	.file_inode_ops	= &nfs_file_inode_operations,
1788ea6e3   Jeff Layton   nfs: when attempt...
725
  	.file_ops	= &nfs_file_operations,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
727
728
729
730
731
  	.getroot	= nfs_proc_get_root,
  	.getattr	= nfs_proc_getattr,
  	.setattr	= nfs_proc_setattr,
  	.lookup		= nfs_proc_lookup,
  	.access		= NULL,		       /* access */
  	.readlink	= nfs_proc_readlink,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
735
736
  	.create		= nfs_proc_create,
  	.remove		= nfs_proc_remove,
  	.unlink_setup	= nfs_proc_unlink_setup,
  	.unlink_done	= nfs_proc_unlink_done,
  	.rename		= nfs_proc_rename,
d3d4152a5   Jeff Layton   nfs: make sillyre...
737
738
  	.rename_setup	= nfs_proc_rename_setup,
  	.rename_done	= nfs_proc_rename_done,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
741
742
743
744
745
746
747
  	.link		= nfs_proc_link,
  	.symlink	= nfs_proc_symlink,
  	.mkdir		= nfs_proc_mkdir,
  	.rmdir		= nfs_proc_rmdir,
  	.readdir	= nfs_proc_readdir,
  	.mknod		= nfs_proc_mknod,
  	.statfs		= nfs_proc_statfs,
  	.fsinfo		= nfs_proc_fsinfo,
  	.pathconf	= nfs_proc_pathconf,
f796f8b3a   Chuck Lever   NFS: Introduce ne...
748
  	.decode_dirent	= nfs2_decode_dirent,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
  	.read_setup	= nfs_proc_read_setup,
ec06c096e   Trond Myklebust   NFS: Cleanup of N...
750
  	.read_done	= nfs_read_done,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  	.write_setup	= nfs_proc_write_setup,
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
752
  	.write_done	= nfs_write_done,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  	.commit_setup	= nfs_proc_commit_setup,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
  	.lock		= nfs_proc_lock,
2116271a3   Trond Myklebust   NFS: Add correct ...
755
  	.lock_check_bounds = nfs_lock_check_bounds,
7fe5c398f   Trond Myklebust   NFS: Optimise NFS...
756
  	.close_context	= nfs_close_context,
45a52a020   Andy Adamson   NFS move nfs_clie...
757
  	.init_client	= nfs_init_client,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
  };