aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/export.c6
-rw-r--r--fs/nfsd/nfs3xdr.c3
-rw-r--r--fs/nfsd/nfs4xdr.c9
-rw-r--r--fs/nfsd/nfscache.c3
-rw-r--r--fs/nfsd/nfsctl.c98
-rw-r--r--fs/nfsd/nfssvc.c80
-rw-r--r--fs/nfsd/vfs.c9
7 files changed, 165 insertions, 43 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 057aff745506..417ec02df44f 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -190,8 +190,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
190 out: 190 out:
191 if (dom) 191 if (dom)
192 auth_domain_put(dom); 192 auth_domain_put(dom);
193 if (buf) 193 kfree(buf);
194 kfree(buf);
195 return err; 194 return err;
196} 195}
197 196
@@ -428,8 +427,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
428 path_release(&nd); 427 path_release(&nd);
429 if (dom) 428 if (dom)
430 auth_domain_put(dom); 429 auth_domain_put(dom);
431 if (buf) 430 kfree(buf);
432 kfree(buf);
433 return err; 431 return err;
434} 432}
435 433
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index e0e134d6baba..9147b8524d05 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -366,7 +366,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
366 len = args->len = ntohl(*p++); 366 len = args->len = ntohl(*p++);
367 367
368 hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; 368 hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
369 if (rqstp->rq_arg.len < len + hdr) 369 if (rqstp->rq_arg.len < hdr ||
370 rqstp->rq_arg.len - hdr < len)
370 return 0; 371 return 0;
371 372
372 args->vec[0].iov_base = (void*)p; 373 args->vec[0].iov_base = (void*)p;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 4c4146350236..dcd673186944 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -151,8 +151,7 @@ static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
151 if (nbytes <= sizeof(argp->tmp)) 151 if (nbytes <= sizeof(argp->tmp))
152 p = argp->tmp; 152 p = argp->tmp;
153 else { 153 else {
154 if (argp->tmpp) 154 kfree(argp->tmpp);
155 kfree(argp->tmpp);
156 p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL); 155 p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL);
157 if (!p) 156 if (!p)
158 return NULL; 157 return NULL;
@@ -2476,10 +2475,8 @@ void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args)
2476 kfree(args->ops); 2475 kfree(args->ops);
2477 args->ops = args->iops; 2476 args->ops = args->iops;
2478 } 2477 }
2479 if (args->tmpp) { 2478 kfree(args->tmpp);
2480 kfree(args->tmpp); 2479 args->tmpp = NULL;
2481 args->tmpp = NULL;
2482 }
2483 while (args->to_free) { 2480 while (args->to_free) {
2484 struct tmpbuf *tb = args->to_free; 2481 struct tmpbuf *tb = args->to_free;
2485 args->to_free = tb->next; 2482 args->to_free = tb->next;
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 119e4d4495b8..d852ebb538e3 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -93,8 +93,7 @@ nfsd_cache_shutdown(void)
93 93
94 cache_disabled = 1; 94 cache_disabled = 1;
95 95
96 if (hash_list) 96 kfree (hash_list);
97 kfree (hash_list);
98 hash_list = NULL; 97 hash_list = NULL;
99} 98}
100 99
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 841c562991e8..a0871b3efeb7 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -23,6 +23,7 @@
23#include <linux/seq_file.h> 23#include <linux/seq_file.h>
24#include <linux/pagemap.h> 24#include <linux/pagemap.h>
25#include <linux/init.h> 25#include <linux/init.h>
26#include <linux/string.h>
26 27
27#include <linux/nfs.h> 28#include <linux/nfs.h>
28#include <linux/nfsd_idmap.h> 29#include <linux/nfsd_idmap.h>
@@ -35,6 +36,8 @@
35 36
36#include <asm/uaccess.h> 37#include <asm/uaccess.h>
37 38
39unsigned int nfsd_versbits = ~0;
40
38/* 41/*
39 * We have a single directory with 9 nodes in it. 42 * We have a single directory with 9 nodes in it.
40 */ 43 */
@@ -50,8 +53,15 @@ enum {
50 NFSD_List, 53 NFSD_List,
51 NFSD_Fh, 54 NFSD_Fh,
52 NFSD_Threads, 55 NFSD_Threads,
56 NFSD_Versions,
57 /*
58 * The below MUST come last. Otherwise we leave a hole in nfsd_files[]
59 * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
60 */
61#ifdef CONFIG_NFSD_V4
53 NFSD_Leasetime, 62 NFSD_Leasetime,
54 NFSD_RecoveryDir, 63 NFSD_RecoveryDir,
64#endif
55}; 65};
56 66
57/* 67/*
@@ -66,8 +76,11 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size);
66static ssize_t write_getfs(struct file *file, char *buf, size_t size); 76static ssize_t write_getfs(struct file *file, char *buf, size_t size);
67static ssize_t write_filehandle(struct file *file, char *buf, size_t size); 77static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
68static ssize_t write_threads(struct file *file, char *buf, size_t size); 78static ssize_t write_threads(struct file *file, char *buf, size_t size);
79static ssize_t write_versions(struct file *file, char *buf, size_t size);
80#ifdef CONFIG_NFSD_V4
69static ssize_t write_leasetime(struct file *file, char *buf, size_t size); 81static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
70static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); 82static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
83#endif
71 84
72static ssize_t (*write_op[])(struct file *, char *, size_t) = { 85static ssize_t (*write_op[])(struct file *, char *, size_t) = {
73 [NFSD_Svc] = write_svc, 86 [NFSD_Svc] = write_svc,
@@ -79,8 +92,11 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
79 [NFSD_Getfs] = write_getfs, 92 [NFSD_Getfs] = write_getfs,
80 [NFSD_Fh] = write_filehandle, 93 [NFSD_Fh] = write_filehandle,
81 [NFSD_Threads] = write_threads, 94 [NFSD_Threads] = write_threads,
95 [NFSD_Versions] = write_versions,
96#ifdef CONFIG_NFSD_V4
82 [NFSD_Leasetime] = write_leasetime, 97 [NFSD_Leasetime] = write_leasetime,
83 [NFSD_RecoveryDir] = write_recoverydir, 98 [NFSD_RecoveryDir] = write_recoverydir,
99#endif
84}; 100};
85 101
86static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) 102static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
@@ -104,9 +120,23 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu
104 return rv; 120 return rv;
105} 121}
106 122
123static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
124{
125 if (! file->private_data) {
126 /* An attempt to read a transaction file without writing
127 * causes a 0-byte write so that the file can return
128 * state information
129 */
130 ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
131 if (rv < 0)
132 return rv;
133 }
134 return simple_transaction_read(file, buf, size, pos);
135}
136
107static struct file_operations transaction_ops = { 137static struct file_operations transaction_ops = {
108 .write = nfsctl_transaction_write, 138 .write = nfsctl_transaction_write,
109 .read = simple_transaction_read, 139 .read = nfsctl_transaction_read,
110 .release = simple_transaction_release, 140 .release = simple_transaction_release,
111}; 141};
112 142
@@ -329,6 +359,70 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
329 return strlen(buf); 359 return strlen(buf);
330} 360}
331 361
362static ssize_t write_versions(struct file *file, char *buf, size_t size)
363{
364 /*
365 * Format:
366 * [-/+]vers [-/+]vers ...
367 */
368 char *mesg = buf;
369 char *vers, sign;
370 int len, num;
371 ssize_t tlen = 0;
372 char *sep;
373
374 if (size>0) {
375 if (nfsd_serv)
376 return -EBUSY;
377 if (buf[size-1] != '\n')
378 return -EINVAL;
379 buf[size-1] = 0;
380
381 vers = mesg;
382 len = qword_get(&mesg, vers, size);
383 if (len <= 0) return -EINVAL;
384 do {
385 sign = *vers;
386 if (sign == '+' || sign == '-')
387 num = simple_strtol((vers+1), NULL, 0);
388 else
389 num = simple_strtol(vers, NULL, 0);
390 switch(num) {
391 case 2:
392 case 3:
393 case 4:
394 if (sign != '-')
395 NFSCTL_VERSET(nfsd_versbits, num);
396 else
397 NFSCTL_VERUNSET(nfsd_versbits, num);
398 break;
399 default:
400 return -EINVAL;
401 }
402 vers += len + 1;
403 tlen += len;
404 } while ((len = qword_get(&mesg, vers, size)) > 0);
405 /* If all get turned off, turn them back on, as
406 * having no versions is BAD
407 */
408 if ((nfsd_versbits & NFSCTL_VERALL)==0)
409 nfsd_versbits = NFSCTL_VERALL;
410 }
411 /* Now write current state into reply buffer */
412 len = 0;
413 sep = "";
414 for (num=2 ; num <= 4 ; num++)
415 if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) {
416 len += sprintf(buf+len, "%s%c%d", sep,
417 NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-',
418 num);
419 sep = " ";
420 }
421 len += sprintf(buf+len, "\n");
422 return len;
423}
424
425#ifdef CONFIG_NFSD_V4
332extern time_t nfs4_leasetime(void); 426extern time_t nfs4_leasetime(void);
333 427
334static ssize_t write_leasetime(struct file *file, char *buf, size_t size) 428static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
@@ -370,6 +464,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
370 status = nfs4_reset_recoverydir(recdir); 464 status = nfs4_reset_recoverydir(recdir);
371 return strlen(buf); 465 return strlen(buf);
372} 466}
467#endif
373 468
374/*----------------------------------------------------------------------------*/ 469/*----------------------------------------------------------------------------*/
375/* 470/*
@@ -389,6 +484,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
389 [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, 484 [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
390 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, 485 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
391 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, 486 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
487 [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
392#ifdef CONFIG_NFSD_V4 488#ifdef CONFIG_NFSD_V4
393 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, 489 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
394 [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, 490 [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 1697539a7171..89ed04696865 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -30,6 +30,7 @@
30#include <linux/nfsd/nfsd.h> 30#include <linux/nfsd/nfsd.h>
31#include <linux/nfsd/stats.h> 31#include <linux/nfsd/stats.h>
32#include <linux/nfsd/cache.h> 32#include <linux/nfsd/cache.h>
33#include <linux/nfsd/syscall.h>
33#include <linux/lockd/bind.h> 34#include <linux/lockd/bind.h>
34#include <linux/nfsacl.h> 35#include <linux/nfsacl.h>
35 36
@@ -52,7 +53,7 @@
52extern struct svc_program nfsd_program; 53extern struct svc_program nfsd_program;
53static void nfsd(struct svc_rqst *rqstp); 54static void nfsd(struct svc_rqst *rqstp);
54struct timeval nfssvc_boot; 55struct timeval nfssvc_boot;
55static struct svc_serv *nfsd_serv; 56 struct svc_serv *nfsd_serv;
56static atomic_t nfsd_busy; 57static atomic_t nfsd_busy;
57static unsigned long nfsd_last_call; 58static unsigned long nfsd_last_call;
58static DEFINE_SPINLOCK(nfsd_call_lock); 59static DEFINE_SPINLOCK(nfsd_call_lock);
@@ -63,6 +64,31 @@ struct nfsd_list {
63}; 64};
64static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list); 65static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list);
65 66
67static struct svc_version * nfsd_version[] = {
68 [2] = &nfsd_version2,
69#if defined(CONFIG_NFSD_V3)
70 [3] = &nfsd_version3,
71#endif
72#if defined(CONFIG_NFSD_V4)
73 [4] = &nfsd_version4,
74#endif
75};
76
77#define NFSD_MINVERS 2
78#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
79static struct svc_version *nfsd_versions[NFSD_NRVERS];
80
81struct svc_program nfsd_program = {
82 .pg_prog = NFS_PROGRAM, /* program number */
83 .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
84 .pg_vers = nfsd_versions, /* version table */
85 .pg_name = "nfsd", /* program name */
86 .pg_class = "nfsd", /* authentication class */
87 .pg_stats = &nfsd_svcstats, /* version table */
88 .pg_authenticate = &svc_set_client, /* export authentication */
89
90};
91
66/* 92/*
67 * Maximum number of nfsd processes 93 * Maximum number of nfsd processes
68 */ 94 */
@@ -80,11 +106,12 @@ int
80nfsd_svc(unsigned short port, int nrservs) 106nfsd_svc(unsigned short port, int nrservs)
81{ 107{
82 int error; 108 int error;
83 int none_left; 109 int none_left, found_one, i;
84 struct list_head *victim; 110 struct list_head *victim;
85 111
86 lock_kernel(); 112 lock_kernel();
87 dprintk("nfsd: creating service\n"); 113 dprintk("nfsd: creating service: vers 0x%x\n",
114 nfsd_versbits);
88 error = -EINVAL; 115 error = -EINVAL;
89 if (nrservs <= 0) 116 if (nrservs <= 0)
90 nrservs = 0; 117 nrservs = 0;
@@ -99,6 +126,27 @@ nfsd_svc(unsigned short port, int nrservs)
99 if (error<0) 126 if (error<0)
100 goto out; 127 goto out;
101 if (!nfsd_serv) { 128 if (!nfsd_serv) {
129 /*
130 * Use the nfsd_ctlbits to define which
131 * versions that will be advertised.
132 * If nfsd_ctlbits doesn't list any version,
133 * export them all.
134 */
135 found_one = 0;
136
137 for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
138 if (NFSCTL_VERISSET(nfsd_versbits, i)) {
139 nfsd_program.pg_vers[i] = nfsd_version[i];
140 found_one = 1;
141 } else
142 nfsd_program.pg_vers[i] = NULL;
143 }
144
145 if (!found_one) {
146 for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
147 nfsd_program.pg_vers[i] = nfsd_version[i];
148 }
149
102 atomic_set(&nfsd_busy, 0); 150 atomic_set(&nfsd_busy, 0);
103 error = -ENOMEM; 151 error = -ENOMEM;
104 nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE); 152 nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE);
@@ -379,6 +427,7 @@ static struct svc_program nfsd_acl_program = {
379 .pg_name = "nfsd", 427 .pg_name = "nfsd",
380 .pg_class = "nfsd", 428 .pg_class = "nfsd",
381 .pg_stats = &nfsd_acl_svcstats, 429 .pg_stats = &nfsd_acl_svcstats,
430 .pg_authenticate = &svc_set_client,
382}; 431};
383 432
384static struct svc_stat nfsd_acl_svcstats = { 433static struct svc_stat nfsd_acl_svcstats = {
@@ -389,28 +438,3 @@ static struct svc_stat nfsd_acl_svcstats = {
389#else 438#else
390#define nfsd_acl_program_p NULL 439#define nfsd_acl_program_p NULL
391#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ 440#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
392
393extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4;
394
395static struct svc_version * nfsd_version[] = {
396 [2] = &nfsd_version2,
397#if defined(CONFIG_NFSD_V3)
398 [3] = &nfsd_version3,
399#endif
400#if defined(CONFIG_NFSD_V4)
401 [4] = &nfsd_version4,
402#endif
403};
404
405#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
406struct svc_program nfsd_program = {
407 .pg_next = nfsd_acl_program_p,
408 .pg_prog = NFS_PROGRAM, /* program number */
409 .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
410 .pg_vers = nfsd_version, /* version table */
411 .pg_name = "nfsd", /* program name */
412 .pg_class = "nfsd", /* authentication class */
413 .pg_stats = &nfsd_svcstats, /* version table */
414 .pg_authenticate = &svc_set_client, /* export authentication */
415
416};
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 4f2cd3d27566..af7c3c3074b0 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -254,12 +254,19 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
254 254
255 /* Get inode */ 255 /* Get inode */
256 err = fh_verify(rqstp, fhp, ftype, accmode); 256 err = fh_verify(rqstp, fhp, ftype, accmode);
257 if (err || !iap->ia_valid) 257 if (err)
258 goto out; 258 goto out;
259 259
260 dentry = fhp->fh_dentry; 260 dentry = fhp->fh_dentry;
261 inode = dentry->d_inode; 261 inode = dentry->d_inode;
262 262
263 /* Ignore any mode updates on symlinks */
264 if (S_ISLNK(inode->i_mode))
265 iap->ia_valid &= ~ATTR_MODE;
266
267 if (!iap->ia_valid)
268 goto out;
269
263 /* NFSv2 does not differentiate between "set-[ac]time-to-now" 270 /* NFSv2 does not differentiate between "set-[ac]time-to-now"
264 * which only requires access, and "set-[ac]time-to-X" which 271 * which only requires access, and "set-[ac]time-to-X" which
265 * requires ownership. 272 * requires ownership.