1 /* 2 * linux/fs/nfsd/nfsctl.c 3 * 4 * Syscall interface to knfsd. 5 * 6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 7 */ 8 9 #include <linux/module.h> 10 11 #include <linux/linkage.h> 12 #include <linux/time.h> 13 #include <linux/errno.h> 14 #include <linux/fs.h> 15 #include <linux/namei.h> 16 #include <linux/fcntl.h> 17 #include <linux/net.h> 18 #include <linux/in.h> 19 #include <linux/syscalls.h> 20 #include <linux/unistd.h> 21 #include <linux/slab.h> 22 #include <linux/proc_fs.h> 23 #include <linux/seq_file.h> 24 #include <linux/pagemap.h> 25 #include <linux/init.h> 26 #include <linux/inet.h> 27 #include <linux/string.h> 28 #include <linux/smp_lock.h> 29 #include <linux/ctype.h> 30 31 #include <linux/nfs.h> 32 #include <linux/nfsd_idmap.h> 33 #include <linux/lockd/bind.h> 34 #include <linux/sunrpc/svc.h> 35 #include <linux/sunrpc/svcsock.h> 36 #include <linux/nfsd/nfsd.h> 37 #include <linux/nfsd/cache.h> 38 #include <linux/nfsd/xdr.h> 39 #include <linux/nfsd/syscall.h> 40 #include <linux/lockd/lockd.h> 41 42 #include <asm/uaccess.h> 43 #include <net/ipv6.h> 44 45 /* 46 * We have a single directory with 9 nodes in it. 47 */ 48 enum { 49 NFSD_Root = 1, 50 NFSD_Svc, 51 NFSD_Add, 52 NFSD_Del, 53 NFSD_Export, 54 NFSD_Unexport, 55 NFSD_Getfd, 56 NFSD_Getfs, 57 NFSD_List, 58 NFSD_Fh, 59 NFSD_FO_UnlockIP, 60 NFSD_FO_UnlockFS, 61 NFSD_Threads, 62 NFSD_Pool_Threads, 63 NFSD_Pool_Stats, 64 NFSD_Versions, 65 NFSD_Ports, 66 NFSD_MaxBlkSize, 67 /* 68 * The below MUST come last. Otherwise we leave a hole in nfsd_files[] 69 * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops 70 */ 71 #ifdef CONFIG_NFSD_V4 72 NFSD_Leasetime, 73 NFSD_RecoveryDir, 74 #endif 75 }; 76 77 /* 78 * write() for these nodes. 79 */ 80 static ssize_t write_svc(struct file *file, char *buf, size_t size); 81 static ssize_t write_add(struct file *file, char *buf, size_t size); 82 static ssize_t write_del(struct file *file, char *buf, size_t size); 83 static ssize_t write_export(struct file *file, char *buf, size_t size); 84 static ssize_t write_unexport(struct file *file, char *buf, size_t size); 85 static ssize_t write_getfd(struct file *file, char *buf, size_t size); 86 static ssize_t write_getfs(struct file *file, char *buf, size_t size); 87 static ssize_t write_filehandle(struct file *file, char *buf, size_t size); 88 static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size); 89 static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size); 90 static ssize_t write_threads(struct file *file, char *buf, size_t size); 91 static ssize_t write_pool_threads(struct file *file, char *buf, size_t size); 92 static ssize_t write_versions(struct file *file, char *buf, size_t size); 93 static ssize_t write_ports(struct file *file, char *buf, size_t size); 94 static ssize_t write_maxblksize(struct file *file, char *buf, size_t size); 95 #ifdef CONFIG_NFSD_V4 96 static ssize_t write_leasetime(struct file *file, char *buf, size_t size); 97 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); 98 #endif 99 100 static ssize_t (*write_op[])(struct file *, char *, size_t) = { 101 [NFSD_Svc] = write_svc, 102 [NFSD_Add] = write_add, 103 [NFSD_Del] = write_del, 104 [NFSD_Export] = write_export, 105 [NFSD_Unexport] = write_unexport, 106 [NFSD_Getfd] = write_getfd, 107 [NFSD_Getfs] = write_getfs, 108 [NFSD_Fh] = write_filehandle, 109 [NFSD_FO_UnlockIP] = write_unlock_ip, 110 [NFSD_FO_UnlockFS] = write_unlock_fs, 111 [NFSD_Threads] = write_threads, 112 [NFSD_Pool_Threads] = write_pool_threads, 113 [NFSD_Versions] = write_versions, 114 [NFSD_Ports] = write_ports, 115 [NFSD_MaxBlkSize] = write_maxblksize, 116 #ifdef CONFIG_NFSD_V4 117 [NFSD_Leasetime] = write_leasetime, 118 [NFSD_RecoveryDir] = write_recoverydir, 119 #endif 120 }; 121 122 static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) 123 { 124 ino_t ino = file->f_path.dentry->d_inode->i_ino; 125 char *data; 126 ssize_t rv; 127 128 if (ino >= ARRAY_SIZE(write_op) || !write_op[ino]) 129 return -EINVAL; 130 131 data = simple_transaction_get(file, buf, size); 132 if (IS_ERR(data)) 133 return PTR_ERR(data); 134 135 rv = write_op[ino](file, data, size); 136 if (rv >= 0) { 137 simple_transaction_set(file, rv); 138 rv = size; 139 } 140 return rv; 141 } 142 143 static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) 144 { 145 if (! file->private_data) { 146 /* An attempt to read a transaction file without writing 147 * causes a 0-byte write so that the file can return 148 * state information 149 */ 150 ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos); 151 if (rv < 0) 152 return rv; 153 } 154 return simple_transaction_read(file, buf, size, pos); 155 } 156 157 static const struct file_operations transaction_ops = { 158 .write = nfsctl_transaction_write, 159 .read = nfsctl_transaction_read, 160 .release = simple_transaction_release, 161 }; 162 163 static int exports_open(struct inode *inode, struct file *file) 164 { 165 return seq_open(file, &nfs_exports_op); 166 } 167 168 static const struct file_operations exports_operations = { 169 .open = exports_open, 170 .read = seq_read, 171 .llseek = seq_lseek, 172 .release = seq_release, 173 .owner = THIS_MODULE, 174 }; 175 176 extern int nfsd_pool_stats_open(struct inode *inode, struct file *file); 177 178 static struct file_operations pool_stats_operations = { 179 .open = nfsd_pool_stats_open, 180 .read = seq_read, 181 .llseek = seq_lseek, 182 .release = seq_release, 183 .owner = THIS_MODULE, 184 }; 185 186 /*----------------------------------------------------------------------------*/ 187 /* 188 * payload - write methods 189 */ 190 191 /** 192 * write_svc - Start kernel's NFSD server 193 * 194 * Deprecated. /proc/fs/nfsd/threads is preferred. 195 * Function remains to support old versions of nfs-utils. 196 * 197 * Input: 198 * buf: struct nfsctl_svc 199 * svc_port: port number of this 200 * server's listener 201 * svc_nthreads: number of threads to start 202 * size: size in bytes of passed in nfsctl_svc 203 * Output: 204 * On success: returns zero 205 * On error: return code is negative errno value 206 */ 207 static ssize_t write_svc(struct file *file, char *buf, size_t size) 208 { 209 struct nfsctl_svc *data; 210 if (size < sizeof(*data)) 211 return -EINVAL; 212 data = (struct nfsctl_svc*) buf; 213 return nfsd_svc(data->svc_port, data->svc_nthreads); 214 } 215 216 /** 217 * write_add - Add or modify client entry in auth unix cache 218 * 219 * Deprecated. /proc/net/rpc/auth.unix.ip is preferred. 220 * Function remains to support old versions of nfs-utils. 221 * 222 * Input: 223 * buf: struct nfsctl_client 224 * cl_ident: '\0'-terminated C string 225 * containing domain name 226 * of client 227 * cl_naddr: no. of items in cl_addrlist 228 * cl_addrlist: array of client addresses 229 * cl_fhkeytype: ignored 230 * cl_fhkeylen: ignored 231 * cl_fhkey: ignored 232 * size: size in bytes of passed in nfsctl_client 233 * Output: 234 * On success: returns zero 235 * On error: return code is negative errno value 236 * 237 * Note: Only AF_INET client addresses are passed in, since 238 * nfsctl_client.cl_addrlist contains only in_addr fields for addresses. 239 */ 240 static ssize_t write_add(struct file *file, char *buf, size_t size) 241 { 242 struct nfsctl_client *data; 243 if (size < sizeof(*data)) 244 return -EINVAL; 245 data = (struct nfsctl_client *)buf; 246 return exp_addclient(data); 247 } 248 249 /** 250 * write_del - Remove client from auth unix cache 251 * 252 * Deprecated. /proc/net/rpc/auth.unix.ip is preferred. 253 * Function remains to support old versions of nfs-utils. 254 * 255 * Input: 256 * buf: struct nfsctl_client 257 * cl_ident: '\0'-terminated C string 258 * containing domain name 259 * of client 260 * cl_naddr: ignored 261 * cl_addrlist: ignored 262 * cl_fhkeytype: ignored 263 * cl_fhkeylen: ignored 264 * cl_fhkey: ignored 265 * size: size in bytes of passed in nfsctl_client 266 * Output: 267 * On success: returns zero 268 * On error: return code is negative errno value 269 * 270 * Note: Only AF_INET client addresses are passed in, since 271 * nfsctl_client.cl_addrlist contains only in_addr fields for addresses. 272 */ 273 static ssize_t write_del(struct file *file, char *buf, size_t size) 274 { 275 struct nfsctl_client *data; 276 if (size < sizeof(*data)) 277 return -EINVAL; 278 data = (struct nfsctl_client *)buf; 279 return exp_delclient(data); 280 } 281 282 /** 283 * write_export - Export part or all of a local file system 284 * 285 * Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred. 286 * Function remains to support old versions of nfs-utils. 287 * 288 * Input: 289 * buf: struct nfsctl_export 290 * ex_client: '\0'-terminated C string 291 * containing domain name 292 * of client allowed to access 293 * this export 294 * ex_path: '\0'-terminated C string 295 * containing pathname of 296 * directory in local file system 297 * ex_dev: fsid to use for this export 298 * ex_ino: ignored 299 * ex_flags: export flags for this export 300 * ex_anon_uid: UID to use for anonymous 301 * requests 302 * ex_anon_gid: GID to use for anonymous 303 * requests 304 * size: size in bytes of passed in nfsctl_export 305 * Output: 306 * On success: returns zero 307 * On error: return code is negative errno value 308 */ 309 static ssize_t write_export(struct file *file, char *buf, size_t size) 310 { 311 struct nfsctl_export *data; 312 if (size < sizeof(*data)) 313 return -EINVAL; 314 data = (struct nfsctl_export*)buf; 315 return exp_export(data); 316 } 317 318 /** 319 * write_unexport - Unexport a previously exported file system 320 * 321 * Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred. 322 * Function remains to support old versions of nfs-utils. 323 * 324 * Input: 325 * buf: struct nfsctl_export 326 * ex_client: '\0'-terminated C string 327 * containing domain name 328 * of client no longer allowed 329 * to access this export 330 * ex_path: '\0'-terminated C string 331 * containing pathname of 332 * directory in local file system 333 * ex_dev: ignored 334 * ex_ino: ignored 335 * ex_flags: ignored 336 * ex_anon_uid: ignored 337 * ex_anon_gid: ignored 338 * size: size in bytes of passed in nfsctl_export 339 * Output: 340 * On success: returns zero 341 * On error: return code is negative errno value 342 */ 343 static ssize_t write_unexport(struct file *file, char *buf, size_t size) 344 { 345 struct nfsctl_export *data; 346 347 if (size < sizeof(*data)) 348 return -EINVAL; 349 data = (struct nfsctl_export*)buf; 350 return exp_unexport(data); 351 } 352 353 /** 354 * write_getfs - Get a variable-length NFS file handle by path 355 * 356 * Deprecated. /proc/fs/nfsd/filehandle is preferred. 357 * Function remains to support old versions of nfs-utils. 358 * 359 * Input: 360 * buf: struct nfsctl_fsparm 361 * gd_addr: socket address of client 362 * gd_path: '\0'-terminated C string 363 * containing pathname of 364 * directory in local file system 365 * gd_maxlen: maximum size of returned file 366 * handle 367 * size: size in bytes of passed in nfsctl_fsparm 368 * Output: 369 * On success: passed-in buffer filled with a knfsd_fh structure 370 * (a variable-length raw NFS file handle); 371 * return code is the size in bytes of the file handle 372 * On error: return code is negative errno value 373 * 374 * Note: Only AF_INET client addresses are passed in, since gd_addr 375 * is the same size as a struct sockaddr_in. 376 */ 377 static ssize_t write_getfs(struct file *file, char *buf, size_t size) 378 { 379 struct nfsctl_fsparm *data; 380 struct sockaddr_in *sin; 381 struct auth_domain *clp; 382 int err = 0; 383 struct knfsd_fh *res; 384 struct in6_addr in6; 385 386 if (size < sizeof(*data)) 387 return -EINVAL; 388 data = (struct nfsctl_fsparm*)buf; 389 err = -EPROTONOSUPPORT; 390 if (data->gd_addr.sa_family != AF_INET) 391 goto out; 392 sin = (struct sockaddr_in *)&data->gd_addr; 393 if (data->gd_maxlen > NFS3_FHSIZE) 394 data->gd_maxlen = NFS3_FHSIZE; 395 396 res = (struct knfsd_fh*)buf; 397 398 exp_readlock(); 399 400 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); 401 402 clp = auth_unix_lookup(&in6); 403 if (!clp) 404 err = -EPERM; 405 else { 406 err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); 407 auth_domain_put(clp); 408 } 409 exp_readunlock(); 410 if (err == 0) 411 err = res->fh_size + offsetof(struct knfsd_fh, fh_base); 412 out: 413 return err; 414 } 415 416 /** 417 * write_getfd - Get a fixed-length NFS file handle by path (used by mountd) 418 * 419 * Deprecated. /proc/fs/nfsd/filehandle is preferred. 420 * Function remains to support old versions of nfs-utils. 421 * 422 * Input: 423 * buf: struct nfsctl_fdparm 424 * gd_addr: socket address of client 425 * gd_path: '\0'-terminated C string 426 * containing pathname of 427 * directory in local file system 428 * gd_version: fdparm structure version 429 * size: size in bytes of passed in nfsctl_fdparm 430 * Output: 431 * On success: passed-in buffer filled with nfsctl_res 432 * (a fixed-length raw NFS file handle); 433 * return code is the size in bytes of the file handle 434 * On error: return code is negative errno value 435 * 436 * Note: Only AF_INET client addresses are passed in, since gd_addr 437 * is the same size as a struct sockaddr_in. 438 */ 439 static ssize_t write_getfd(struct file *file, char *buf, size_t size) 440 { 441 struct nfsctl_fdparm *data; 442 struct sockaddr_in *sin; 443 struct auth_domain *clp; 444 int err = 0; 445 struct knfsd_fh fh; 446 char *res; 447 struct in6_addr in6; 448 449 if (size < sizeof(*data)) 450 return -EINVAL; 451 data = (struct nfsctl_fdparm*)buf; 452 err = -EPROTONOSUPPORT; 453 if (data->gd_addr.sa_family != AF_INET) 454 goto out; 455 err = -EINVAL; 456 if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS) 457 goto out; 458 459 res = buf; 460 sin = (struct sockaddr_in *)&data->gd_addr; 461 exp_readlock(); 462 463 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); 464 465 clp = auth_unix_lookup(&in6); 466 if (!clp) 467 err = -EPERM; 468 else { 469 err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); 470 auth_domain_put(clp); 471 } 472 exp_readunlock(); 473 474 if (err == 0) { 475 memset(res,0, NFS_FHSIZE); 476 memcpy(res, &fh.fh_base, fh.fh_size); 477 err = NFS_FHSIZE; 478 } 479 out: 480 return err; 481 } 482 483 /** 484 * write_unlock_ip - Release all locks used by a client 485 * 486 * Experimental. 487 * 488 * Input: 489 * buf: '\n'-terminated C string containing a 490 * presentation format IPv4 address 491 * size: length of C string in @buf 492 * Output: 493 * On success: returns zero if all specified locks were released; 494 * returns one if one or more locks were not released 495 * On error: return code is negative errno value 496 * 497 * Note: Only AF_INET client addresses are passed in 498 */ 499 static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) 500 { 501 struct sockaddr_in sin = { 502 .sin_family = AF_INET, 503 }; 504 int b1, b2, b3, b4; 505 char c; 506 char *fo_path; 507 508 /* sanity check */ 509 if (size == 0) 510 return -EINVAL; 511 512 if (buf[size-1] != '\n') 513 return -EINVAL; 514 515 fo_path = buf; 516 if (qword_get(&buf, fo_path, size) < 0) 517 return -EINVAL; 518 519 /* get ipv4 address */ 520 if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) 521 return -EINVAL; 522 if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255) 523 return -EINVAL; 524 sin.sin_addr.s_addr = htonl((b1 << 24) | (b2 << 16) | (b3 << 8) | b4); 525 526 return nlmsvc_unlock_all_by_ip((struct sockaddr *)&sin); 527 } 528 529 /** 530 * write_unlock_fs - Release all locks on a local file system 531 * 532 * Experimental. 533 * 534 * Input: 535 * buf: '\n'-terminated C string containing the 536 * absolute pathname of a local file system 537 * size: length of C string in @buf 538 * Output: 539 * On success: returns zero if all specified locks were released; 540 * returns one if one or more locks were not released 541 * On error: return code is negative errno value 542 */ 543 static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size) 544 { 545 struct path path; 546 char *fo_path; 547 int error; 548 549 /* sanity check */ 550 if (size == 0) 551 return -EINVAL; 552 553 if (buf[size-1] != '\n') 554 return -EINVAL; 555 556 fo_path = buf; 557 if (qword_get(&buf, fo_path, size) < 0) 558 return -EINVAL; 559 560 error = kern_path(fo_path, 0, &path); 561 if (error) 562 return error; 563 564 /* 565 * XXX: Needs better sanity checking. Otherwise we could end up 566 * releasing locks on the wrong file system. 567 * 568 * For example: 569 * 1. Does the path refer to a directory? 570 * 2. Is that directory a mount point, or 571 * 3. Is that directory the root of an exported file system? 572 */ 573 error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb); 574 575 path_put(&path); 576 return error; 577 } 578 579 /** 580 * write_filehandle - Get a variable-length NFS file handle by path 581 * 582 * On input, the buffer contains a '\n'-terminated C string comprised of 583 * three alphanumeric words separated by whitespace. The string may 584 * contain escape sequences. 585 * 586 * Input: 587 * buf: 588 * domain: client domain name 589 * path: export pathname 590 * maxsize: numeric maximum size of 591 * @buf 592 * size: length of C string in @buf 593 * Output: 594 * On success: passed-in buffer filled with '\n'-terminated C 595 * string containing a ASCII hex text version 596 * of the NFS file handle; 597 * return code is the size in bytes of the string 598 * On error: return code is negative errno value 599 */ 600 static ssize_t write_filehandle(struct file *file, char *buf, size_t size) 601 { 602 char *dname, *path; 603 int uninitialized_var(maxsize); 604 char *mesg = buf; 605 int len; 606 struct auth_domain *dom; 607 struct knfsd_fh fh; 608 609 if (size == 0) 610 return -EINVAL; 611 612 if (buf[size-1] != '\n') 613 return -EINVAL; 614 buf[size-1] = 0; 615 616 dname = mesg; 617 len = qword_get(&mesg, dname, size); 618 if (len <= 0) 619 return -EINVAL; 620 621 path = dname+len+1; 622 len = qword_get(&mesg, path, size); 623 if (len <= 0) 624 return -EINVAL; 625 626 len = get_int(&mesg, &maxsize); 627 if (len) 628 return len; 629 630 if (maxsize < NFS_FHSIZE) 631 return -EINVAL; 632 if (maxsize > NFS3_FHSIZE) 633 maxsize = NFS3_FHSIZE; 634 635 if (qword_get(&mesg, mesg, size)>0) 636 return -EINVAL; 637 638 /* we have all the words, they are in buf.. */ 639 dom = unix_domain_find(dname); 640 if (!dom) 641 return -ENOMEM; 642 643 len = exp_rootfh(dom, path, &fh, maxsize); 644 auth_domain_put(dom); 645 if (len) 646 return len; 647 648 mesg = buf; 649 len = SIMPLE_TRANSACTION_LIMIT; 650 qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); 651 mesg[-1] = '\n'; 652 return mesg - buf; 653 } 654 655 /** 656 * write_threads - Start NFSD, or report the current number of running threads 657 * 658 * Input: 659 * buf: ignored 660 * size: zero 661 * Output: 662 * On success: passed-in buffer filled with '\n'-terminated C 663 * string numeric value representing the number of 664 * running NFSD threads; 665 * return code is the size in bytes of the string 666 * On error: return code is zero 667 * 668 * OR 669 * 670 * Input: 671 * buf: C string containing an unsigned 672 * integer value representing the 673 * number of NFSD threads to start 674 * size: non-zero length of C string in @buf 675 * Output: 676 * On success: NFS service is started; 677 * passed-in buffer filled with '\n'-terminated C 678 * string numeric value representing the number of 679 * running NFSD threads; 680 * return code is the size in bytes of the string 681 * On error: return code is zero or a negative errno value 682 */ 683 static ssize_t write_threads(struct file *file, char *buf, size_t size) 684 { 685 char *mesg = buf; 686 int rv; 687 if (size > 0) { 688 int newthreads; 689 rv = get_int(&mesg, &newthreads); 690 if (rv) 691 return rv; 692 if (newthreads < 0) 693 return -EINVAL; 694 rv = nfsd_svc(NFS_PORT, newthreads); 695 if (rv) 696 return rv; 697 } 698 sprintf(buf, "%d\n", nfsd_nrthreads()); 699 return strlen(buf); 700 } 701 702 /** 703 * write_pool_threads - Set or report the current number of threads per pool 704 * 705 * Input: 706 * buf: ignored 707 * size: zero 708 * 709 * OR 710 * 711 * Input: 712 * buf: C string containing whitespace- 713 * separated unsigned integer values 714 * representing the number of NFSD 715 * threads to start in each pool 716 * size: non-zero length of C string in @buf 717 * Output: 718 * On success: passed-in buffer filled with '\n'-terminated C 719 * string containing integer values representing the 720 * number of NFSD threads in each pool; 721 * return code is the size in bytes of the string 722 * On error: return code is zero or a negative errno value 723 */ 724 static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) 725 { 726 /* if size > 0, look for an array of number of threads per node 727 * and apply them then write out number of threads per node as reply 728 */ 729 char *mesg = buf; 730 int i; 731 int rv; 732 int len; 733 int npools; 734 int *nthreads; 735 736 mutex_lock(&nfsd_mutex); 737 npools = nfsd_nrpools(); 738 if (npools == 0) { 739 /* 740 * NFS is shut down. The admin can start it by 741 * writing to the threads file but NOT the pool_threads 742 * file, sorry. Report zero threads. 743 */ 744 mutex_unlock(&nfsd_mutex); 745 strcpy(buf, "0\n"); 746 return strlen(buf); 747 } 748 749 nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL); 750 rv = -ENOMEM; 751 if (nthreads == NULL) 752 goto out_free; 753 754 if (size > 0) { 755 for (i = 0; i < npools; i++) { 756 rv = get_int(&mesg, &nthreads[i]); 757 if (rv == -ENOENT) 758 break; /* fewer numbers than pools */ 759 if (rv) 760 goto out_free; /* syntax error */ 761 rv = -EINVAL; 762 if (nthreads[i] < 0) 763 goto out_free; 764 } 765 rv = nfsd_set_nrthreads(i, nthreads); 766 if (rv) 767 goto out_free; 768 } 769 770 rv = nfsd_get_nrthreads(npools, nthreads); 771 if (rv) 772 goto out_free; 773 774 mesg = buf; 775 size = SIMPLE_TRANSACTION_LIMIT; 776 for (i = 0; i < npools && size > 0; i++) { 777 snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' ')); 778 len = strlen(mesg); 779 size -= len; 780 mesg += len; 781 } 782 783 mutex_unlock(&nfsd_mutex); 784 return (mesg-buf); 785 786 out_free: 787 kfree(nthreads); 788 mutex_unlock(&nfsd_mutex); 789 return rv; 790 } 791 792 static ssize_t __write_versions(struct file *file, char *buf, size_t size) 793 { 794 char *mesg = buf; 795 char *vers, *minorp, sign; 796 int len, num; 797 unsigned minor; 798 ssize_t tlen = 0; 799 char *sep; 800 801 if (size>0) { 802 if (nfsd_serv) 803 /* Cannot change versions without updating 804 * nfsd_serv->sv_xdrsize, and reallocing 805 * rq_argp and rq_resp 806 */ 807 return -EBUSY; 808 if (buf[size-1] != '\n') 809 return -EINVAL; 810 buf[size-1] = 0; 811 812 vers = mesg; 813 len = qword_get(&mesg, vers, size); 814 if (len <= 0) return -EINVAL; 815 do { 816 sign = *vers; 817 if (sign == '+' || sign == '-') 818 num = simple_strtol((vers+1), &minorp, 0); 819 else 820 num = simple_strtol(vers, &minorp, 0); 821 if (*minorp == '.') { 822 if (num < 4) 823 return -EINVAL; 824 minor = simple_strtoul(minorp+1, NULL, 0); 825 if (minor == 0) 826 return -EINVAL; 827 if (nfsd_minorversion(minor, sign == '-' ? 828 NFSD_CLEAR : NFSD_SET) < 0) 829 return -EINVAL; 830 goto next; 831 } 832 switch(num) { 833 case 2: 834 case 3: 835 case 4: 836 nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET); 837 break; 838 default: 839 return -EINVAL; 840 } 841 next: 842 vers += len + 1; 843 tlen += len; 844 } while ((len = qword_get(&mesg, vers, size)) > 0); 845 /* If all get turned off, turn them back on, as 846 * having no versions is BAD 847 */ 848 nfsd_reset_versions(); 849 } 850 /* Now write current state into reply buffer */ 851 len = 0; 852 sep = ""; 853 for (num=2 ; num <= 4 ; num++) 854 if (nfsd_vers(num, NFSD_AVAIL)) { 855 len += sprintf(buf+len, "%s%c%d", sep, 856 nfsd_vers(num, NFSD_TEST)?'+':'-', 857 num); 858 sep = " "; 859 } 860 if (nfsd_vers(4, NFSD_AVAIL)) 861 for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; minor++) 862 len += sprintf(buf+len, " %c4.%u", 863 (nfsd_vers(4, NFSD_TEST) && 864 nfsd_minorversion(minor, NFSD_TEST)) ? 865 '+' : '-', 866 minor); 867 len += sprintf(buf+len, "\n"); 868 return len; 869 } 870 871 /** 872 * write_versions - Set or report the available NFS protocol versions 873 * 874 * Input: 875 * buf: ignored 876 * size: zero 877 * Output: 878 * On success: passed-in buffer filled with '\n'-terminated C 879 * string containing positive or negative integer 880 * values representing the current status of each 881 * protocol version; 882 * return code is the size in bytes of the string 883 * On error: return code is zero or a negative errno value 884 * 885 * OR 886 * 887 * Input: 888 * buf: C string containing whitespace- 889 * separated positive or negative 890 * integer values representing NFS 891 * protocol versions to enable ("+n") 892 * or disable ("-n") 893 * size: non-zero length of C string in @buf 894 * Output: 895 * On success: status of zero or more protocol versions has 896 * been updated; passed-in buffer filled with 897 * '\n'-terminated C string containing positive 898 * or negative integer values representing the 899 * current status of each protocol version; 900 * return code is the size in bytes of the string 901 * On error: return code is zero or a negative errno value 902 */ 903 static ssize_t write_versions(struct file *file, char *buf, size_t size) 904 { 905 ssize_t rv; 906 907 mutex_lock(&nfsd_mutex); 908 rv = __write_versions(file, buf, size); 909 mutex_unlock(&nfsd_mutex); 910 return rv; 911 } 912 913 static ssize_t __write_ports(struct file *file, char *buf, size_t size) 914 { 915 if (size == 0) { 916 int len = 0; 917 918 if (nfsd_serv) 919 len = svc_xprt_names(nfsd_serv, buf, 0); 920 return len; 921 } 922 /* Either a single 'fd' number is written, in which 923 * case it must be for a socket of a supported family/protocol, 924 * and we use it as an nfsd socket, or 925 * A '-' followed by the 'name' of a socket in which case 926 * we close the socket. 927 */ 928 if (isdigit(buf[0])) { 929 char *mesg = buf; 930 int fd; 931 int err; 932 err = get_int(&mesg, &fd); 933 if (err) 934 return -EINVAL; 935 if (fd < 0) 936 return -EINVAL; 937 err = nfsd_create_serv(); 938 if (!err) { 939 err = svc_addsock(nfsd_serv, fd, buf); 940 if (err >= 0) { 941 err = lockd_up(); 942 if (err < 0) 943 svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf); 944 } 945 /* Decrease the count, but don't shutdown the 946 * the service 947 */ 948 nfsd_serv->sv_nrthreads--; 949 } 950 return err < 0 ? err : 0; 951 } 952 if (buf[0] == '-' && isdigit(buf[1])) { 953 char *toclose = kstrdup(buf+1, GFP_KERNEL); 954 int len = 0; 955 if (!toclose) 956 return -ENOMEM; 957 if (nfsd_serv) 958 len = svc_sock_names(buf, nfsd_serv, toclose); 959 if (len >= 0) 960 lockd_down(); 961 kfree(toclose); 962 return len; 963 } 964 /* 965 * Add a transport listener by writing it's transport name 966 */ 967 if (isalpha(buf[0])) { 968 int err; 969 char transport[16]; 970 int port; 971 if (sscanf(buf, "%15s %4d", transport, &port) == 2) { 972 if (port < 1 || port > 65535) 973 return -EINVAL; 974 err = nfsd_create_serv(); 975 if (!err) { 976 err = svc_create_xprt(nfsd_serv, 977 transport, PF_INET, port, 978 SVC_SOCK_ANONYMOUS); 979 if (err == -ENOENT) 980 /* Give a reasonable perror msg for 981 * bad transport string */ 982 err = -EPROTONOSUPPORT; 983 } 984 return err < 0 ? err : 0; 985 } 986 } 987 /* 988 * Remove a transport by writing it's transport name and port number 989 */ 990 if (buf[0] == '-' && isalpha(buf[1])) { 991 struct svc_xprt *xprt; 992 int err = -EINVAL; 993 char transport[16]; 994 int port; 995 if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { 996 if (port < 1 || port > 65535) 997 return -EINVAL; 998 if (nfsd_serv) { 999 xprt = svc_find_xprt(nfsd_serv, transport, 1000 AF_UNSPEC, port); 1001 if (xprt) { 1002 svc_close_xprt(xprt); 1003 svc_xprt_put(xprt); 1004 err = 0; 1005 } else 1006 err = -ENOTCONN; 1007 } 1008 return err < 0 ? err : 0; 1009 } 1010 } 1011 return -EINVAL; 1012 } 1013 1014 /** 1015 * write_ports - Pass a socket file descriptor or transport name to listen on 1016 * 1017 * Input: 1018 * buf: ignored 1019 * size: zero 1020 * Output: 1021 * On success: passed-in buffer filled with a '\n'-terminated C 1022 * string containing a whitespace-separated list of 1023 * named NFSD listeners; 1024 * return code is the size in bytes of the string 1025 * On error: return code is zero or a negative errno value 1026 * 1027 * OR 1028 * 1029 * Input: 1030 * buf: C string containing an unsigned 1031 * integer value representing a bound 1032 * but unconnected socket that is to be 1033 * used as an NFSD listener 1034 * size: non-zero length of C string in @buf 1035 * Output: 1036 * On success: NFS service is started; 1037 * passed-in buffer filled with a '\n'-terminated C 1038 * string containing a unique alphanumeric name of 1039 * the listener; 1040 * return code is the size in bytes of the string 1041 * On error: return code is a negative errno value 1042 * 1043 * OR 1044 * 1045 * Input: 1046 * buf: C string containing a "-" followed 1047 * by an integer value representing a 1048 * previously passed in socket file 1049 * descriptor 1050 * size: non-zero length of C string in @buf 1051 * Output: 1052 * On success: NFS service no longer listens on that socket; 1053 * passed-in buffer filled with a '\n'-terminated C 1054 * string containing a unique name of the listener; 1055 * return code is the size in bytes of the string 1056 * On error: return code is a negative errno value 1057 * 1058 * OR 1059 * 1060 * Input: 1061 * buf: C string containing a transport 1062 * name and an unsigned integer value 1063 * representing the port to listen on, 1064 * separated by whitespace 1065 * size: non-zero length of C string in @buf 1066 * Output: 1067 * On success: returns zero; NFS service is started 1068 * On error: return code is a negative errno value 1069 * 1070 * OR 1071 * 1072 * Input: 1073 * buf: C string containing a "-" followed 1074 * by a transport name and an unsigned 1075 * integer value representing the port 1076 * to listen on, separated by whitespace 1077 * size: non-zero length of C string in @buf 1078 * Output: 1079 * On success: returns zero; NFS service no longer listens 1080 * on that transport 1081 * On error: return code is a negative errno value 1082 */ 1083 static ssize_t write_ports(struct file *file, char *buf, size_t size) 1084 { 1085 ssize_t rv; 1086 1087 mutex_lock(&nfsd_mutex); 1088 rv = __write_ports(file, buf, size); 1089 mutex_unlock(&nfsd_mutex); 1090 return rv; 1091 } 1092 1093 1094 int nfsd_max_blksize; 1095 1096 /** 1097 * write_maxblksize - Set or report the current NFS blksize 1098 * 1099 * Input: 1100 * buf: ignored 1101 * size: zero 1102 * 1103 * OR 1104 * 1105 * Input: 1106 * buf: C string containing an unsigned 1107 * integer value representing the new 1108 * NFS blksize 1109 * size: non-zero length of C string in @buf 1110 * Output: 1111 * On success: passed-in buffer filled with '\n'-terminated C string 1112 * containing numeric value of the current NFS blksize 1113 * setting; 1114 * return code is the size in bytes of the string 1115 * On error: return code is zero or a negative errno value 1116 */ 1117 static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) 1118 { 1119 char *mesg = buf; 1120 if (size > 0) { 1121 int bsize; 1122 int rv = get_int(&mesg, &bsize); 1123 if (rv) 1124 return rv; 1125 /* force bsize into allowed range and 1126 * required alignment. 1127 */ 1128 if (bsize < 1024) 1129 bsize = 1024; 1130 if (bsize > NFSSVC_MAXBLKSIZE) 1131 bsize = NFSSVC_MAXBLKSIZE; 1132 bsize &= ~(1024-1); 1133 mutex_lock(&nfsd_mutex); 1134 if (nfsd_serv && nfsd_serv->sv_nrthreads) { 1135 mutex_unlock(&nfsd_mutex); 1136 return -EBUSY; 1137 } 1138 nfsd_max_blksize = bsize; 1139 mutex_unlock(&nfsd_mutex); 1140 } 1141 return sprintf(buf, "%d\n", nfsd_max_blksize); 1142 } 1143 1144 #ifdef CONFIG_NFSD_V4 1145 extern time_t nfs4_leasetime(void); 1146 1147 static ssize_t __write_leasetime(struct file *file, char *buf, size_t size) 1148 { 1149 /* if size > 10 seconds, call 1150 * nfs4_reset_lease() then write out the new lease (seconds) as reply 1151 */ 1152 char *mesg = buf; 1153 int rv, lease; 1154 1155 if (size > 0) { 1156 if (nfsd_serv) 1157 return -EBUSY; 1158 rv = get_int(&mesg, &lease); 1159 if (rv) 1160 return rv; 1161 if (lease < 10 || lease > 3600) 1162 return -EINVAL; 1163 nfs4_reset_lease(lease); 1164 } 1165 sprintf(buf, "%ld\n", nfs4_lease_time()); 1166 return strlen(buf); 1167 } 1168 1169 /** 1170 * write_leasetime - Set or report the current NFSv4 lease time 1171 * 1172 * Input: 1173 * buf: ignored 1174 * size: zero 1175 * 1176 * OR 1177 * 1178 * Input: 1179 * buf: C string containing an unsigned 1180 * integer value representing the new 1181 * NFSv4 lease expiry time 1182 * size: non-zero length of C string in @buf 1183 * Output: 1184 * On success: passed-in buffer filled with '\n'-terminated C 1185 * string containing unsigned integer value of the 1186 * current lease expiry time; 1187 * return code is the size in bytes of the string 1188 * On error: return code is zero or a negative errno value 1189 */ 1190 static ssize_t write_leasetime(struct file *file, char *buf, size_t size) 1191 { 1192 ssize_t rv; 1193 1194 mutex_lock(&nfsd_mutex); 1195 rv = __write_leasetime(file, buf, size); 1196 mutex_unlock(&nfsd_mutex); 1197 return rv; 1198 } 1199 1200 extern char *nfs4_recoverydir(void); 1201 1202 static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) 1203 { 1204 char *mesg = buf; 1205 char *recdir; 1206 int len, status; 1207 1208 if (size > 0) { 1209 if (nfsd_serv) 1210 return -EBUSY; 1211 if (size > PATH_MAX || buf[size-1] != '\n') 1212 return -EINVAL; 1213 buf[size-1] = 0; 1214 1215 recdir = mesg; 1216 len = qword_get(&mesg, recdir, size); 1217 if (len <= 0) 1218 return -EINVAL; 1219 1220 status = nfs4_reset_recoverydir(recdir); 1221 } 1222 sprintf(buf, "%s\n", nfs4_recoverydir()); 1223 return strlen(buf); 1224 } 1225 1226 /** 1227 * write_recoverydir - Set or report the pathname of the recovery directory 1228 * 1229 * Input: 1230 * buf: ignored 1231 * size: zero 1232 * 1233 * OR 1234 * 1235 * Input: 1236 * buf: C string containing the pathname 1237 * of the directory on a local file 1238 * system containing permanent NFSv4 1239 * recovery data 1240 * size: non-zero length of C string in @buf 1241 * Output: 1242 * On success: passed-in buffer filled with '\n'-terminated C string 1243 * containing the current recovery pathname setting; 1244 * return code is the size in bytes of the string 1245 * On error: return code is zero or a negative errno value 1246 */ 1247 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) 1248 { 1249 ssize_t rv; 1250 1251 mutex_lock(&nfsd_mutex); 1252 rv = __write_recoverydir(file, buf, size); 1253 mutex_unlock(&nfsd_mutex); 1254 return rv; 1255 } 1256 1257 #endif 1258 1259 /*----------------------------------------------------------------------------*/ 1260 /* 1261 * populating the filesystem. 1262 */ 1263 1264 static int nfsd_fill_super(struct super_block * sb, void * data, int silent) 1265 { 1266 static struct tree_descr nfsd_files[] = { 1267 [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR}, 1268 [NFSD_Add] = {".add", &transaction_ops, S_IWUSR}, 1269 [NFSD_Del] = {".del", &transaction_ops, S_IWUSR}, 1270 [NFSD_Export] = {".export", &transaction_ops, S_IWUSR}, 1271 [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR}, 1272 [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, 1273 [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, 1274 [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, 1275 [NFSD_FO_UnlockIP] = {"unlock_ip", 1276 &transaction_ops, S_IWUSR|S_IRUSR}, 1277 [NFSD_FO_UnlockFS] = {"unlock_filesystem", 1278 &transaction_ops, S_IWUSR|S_IRUSR}, 1279 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, 1280 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, 1281 [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, 1282 [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO}, 1283 [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, 1284 [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, 1285 [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO}, 1286 #ifdef CONFIG_NFSD_V4 1287 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, 1288 [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, 1289 #endif 1290 /* last one */ {""} 1291 }; 1292 return simple_fill_super(sb, 0x6e667364, nfsd_files); 1293 } 1294 1295 static int nfsd_get_sb(struct file_system_type *fs_type, 1296 int flags, const char *dev_name, void *data, struct vfsmount *mnt) 1297 { 1298 return get_sb_single(fs_type, flags, data, nfsd_fill_super, mnt); 1299 } 1300 1301 static struct file_system_type nfsd_fs_type = { 1302 .owner = THIS_MODULE, 1303 .name = "nfsd", 1304 .get_sb = nfsd_get_sb, 1305 .kill_sb = kill_litter_super, 1306 }; 1307 1308 #ifdef CONFIG_PROC_FS 1309 static int create_proc_exports_entry(void) 1310 { 1311 struct proc_dir_entry *entry; 1312 1313 entry = proc_mkdir("fs/nfs", NULL); 1314 if (!entry) 1315 return -ENOMEM; 1316 entry = proc_create("exports", 0, entry, &exports_operations); 1317 if (!entry) 1318 return -ENOMEM; 1319 return 0; 1320 } 1321 #else /* CONFIG_PROC_FS */ 1322 static int create_proc_exports_entry(void) 1323 { 1324 return 0; 1325 } 1326 #endif 1327 1328 static int __init init_nfsd(void) 1329 { 1330 int retval; 1331 printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); 1332 1333 retval = nfs4_state_init(); /* nfs4 locking state */ 1334 if (retval) 1335 return retval; 1336 nfsd_stat_init(); /* Statistics */ 1337 retval = nfsd_reply_cache_init(); 1338 if (retval) 1339 goto out_free_stat; 1340 retval = nfsd_export_init(); 1341 if (retval) 1342 goto out_free_cache; 1343 nfsd_lockd_init(); /* lockd->nfsd callbacks */ 1344 retval = nfsd_idmap_init(); 1345 if (retval) 1346 goto out_free_lockd; 1347 retval = create_proc_exports_entry(); 1348 if (retval) 1349 goto out_free_idmap; 1350 retval = register_filesystem(&nfsd_fs_type); 1351 if (retval) 1352 goto out_free_all; 1353 return 0; 1354 out_free_all: 1355 remove_proc_entry("fs/nfs/exports", NULL); 1356 remove_proc_entry("fs/nfs", NULL); 1357 out_free_idmap: 1358 nfsd_idmap_shutdown(); 1359 out_free_lockd: 1360 nfsd_lockd_shutdown(); 1361 nfsd_export_shutdown(); 1362 out_free_cache: 1363 nfsd_reply_cache_shutdown(); 1364 out_free_stat: 1365 nfsd_stat_shutdown(); 1366 nfsd4_free_slabs(); 1367 return retval; 1368 } 1369 1370 static void __exit exit_nfsd(void) 1371 { 1372 nfsd_export_shutdown(); 1373 nfsd_reply_cache_shutdown(); 1374 remove_proc_entry("fs/nfs/exports", NULL); 1375 remove_proc_entry("fs/nfs", NULL); 1376 nfsd_stat_shutdown(); 1377 nfsd_lockd_shutdown(); 1378 nfsd_idmap_shutdown(); 1379 nfsd4_free_slabs(); 1380 unregister_filesystem(&nfsd_fs_type); 1381 } 1382 1383 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); 1384 MODULE_LICENSE("GPL"); 1385 module_init(init_nfsd) 1386 module_exit(exit_nfsd) 1387