static int nfsd_startup(unsigned short port, int nrservs) { int ret; if (nfsd_up) return 0; /* * Readahead param cache - will no-op if it already exists. * (Note therefore results will be suboptimal if number of * threads is modified after nfsd start.) */ ret = nfsd_racache_init(2*nrservs); if (ret) return ret; ret = nfsd_init_socks(port); if (ret) goto out_racache; ret = lockd_up(); if (ret) goto out_racache; ret = nfs4_state_start(); if (ret) goto out_lockd; nfsd_up = true; return 0; out_lockd: lockd_down(); out_racache: nfsd_racache_shutdown(); return ret; }
static int nfsd_startup_net(int nrservs, struct net *net) { struct nfsd_net *nn = net_generic(net, nfsd_net_id); int ret; if (nn->nfsd_net_up) return 0; ret = nfsd_startup_generic(nrservs); if (ret) return ret; ret = nfsd_init_socks(net); if (ret) goto out_socks; ret = lockd_up(net); if (ret) goto out_socks; ret = nfs4_state_start_net(net); if (ret) goto out_lockd; nn->nfsd_net_up = true; return 0; out_lockd: lockd_down(net); out_socks: nfsd_shutdown_generic(); return ret; }
static int nfsd_startup(unsigned short port, int nrservs) { int ret; if (nfsd_up) return 0; /* */ ret = nfsd_racache_init(2*nrservs); if (ret) return ret; ret = nfsd_init_socks(port); if (ret) goto out_racache; ret = lockd_up(); if (ret) goto out_racache; ret = nfs4_state_start(); if (ret) goto out_lockd; nfsd_up = true; return 0; out_lockd: lockd_down(); out_racache: nfsd_racache_shutdown(); return ret; }
static ssize_t write_ports(struct file *file, char *buf, size_t size) { if (size == 0) { int len = 0; lock_kernel(); if (nfsd_serv) len = svc_sock_names(buf, nfsd_serv, NULL); unlock_kernel(); return len; } /* Either a single 'fd' number is written, in which * case it must be for a socket of a supported family/protocol, * and we use it as an nfsd socket, or * A '-' followed by the 'name' of a socket in which case * we close the socket. */ if (isdigit(buf[0])) { char *mesg = buf; int fd; int err; err = get_int(&mesg, &fd); if (err) return -EINVAL; if (fd < 0) return -EINVAL; err = nfsd_create_serv(); if (!err) { int proto = 0; err = svc_addsock(nfsd_serv, fd, buf, &proto); if (err >= 0) { err = lockd_up(proto); if (err < 0) svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf); } /* Decrease the count, but don't shutdown the * the service */ lock_kernel(); nfsd_serv->sv_nrthreads--; unlock_kernel(); } return err < 0 ? err : 0; } if (buf[0] == '-') { char *toclose = kstrdup(buf+1, GFP_KERNEL); int len = 0; if (!toclose) return -ENOMEM; lock_kernel(); if (nfsd_serv) len = svc_sock_names(buf, nfsd_serv, toclose); unlock_kernel(); if (len >= 0) lockd_down(); kfree(toclose); return len; } return -EINVAL; }
static int reclaimer(void *ptr) { struct nlm_host *host = (struct nlm_host *) ptr; struct nlm_wait *block; struct list_head *tmp; /* This one ensures that our parent doesn't terminate while the * reclaim is in progress */ lock_kernel(); lockd_up(); /* First, reclaim all locks that have been granted previously. */ restart: tmp = file_lock_list.next; while (tmp != &file_lock_list) { struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); struct inode *inode = fl->fl_file->f_dentry->d_inode; if (inode->i_sb->s_magic == NFS_SUPER_MAGIC && nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr) && fl->fl_u.nfs_fl.state != host->h_state && (fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) { fl->fl_u.nfs_fl.flags &= ~ NFS_LCK_GRANTED; nlmclnt_reclaim(host, fl); /* This sleeps */ goto restart; } tmp = tmp->next; } host->h_reclaiming = 0; wake_up(&host->h_gracewait); /* Now, wake up all processes that sleep on a blocked lock */ for (block = nlm_blocked; block; block = block->b_next) { if (block->b_host == host) { block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; wake_up(&block->b_wait); } } /* Release host handle after use */ nlm_release_host(host); lockd_down(); unlock_kernel(); return 0; }
/* * The way this works is that the mount process passes a structure * in the data argument which contains the server's IP address * and the root file handle obtained from the server's mount * daemon. We stash these away in the private superblock fields. */ struct super_block * nfs_read_super(struct super_block *sb, void *raw_data, int silent) { struct nfs_mount_data *data = (struct nfs_mount_data *) raw_data; struct nfs_server *server; struct rpc_xprt *xprt; struct rpc_clnt *clnt; struct nfs_fh *root_fh; struct inode *root_inode; unsigned int authflavor; int tcp; struct sockaddr_in srvaddr; struct rpc_timeout timeparms; struct nfs_fattr fattr; MOD_INC_USE_COUNT; if (!data) goto out_miss_args; /* No NFS V3. */ if (data->flags & NFS_MOUNT_VER3) goto out_fail; /* Don't complain if "mount" is newer. */ if (data->version < NFS_MOUNT_VERSION) { printk("nfs warning: mount version %s than kernel\n", data->version < NFS_MOUNT_VERSION ? "older" : "newer"); if (data->version < 2) data->namlen = 0; if (data->version < 3) data->bsize = 0; } /* We now require that the mount process passes the remote address */ memcpy(&srvaddr, &data->addr, sizeof(srvaddr)); if (srvaddr.sin_addr.s_addr == INADDR_ANY) goto out_no_remote; lock_super(sb); sb->s_flags |= MS_ODD_RENAME; /* This should go away */ sb->s_magic = NFS_SUPER_MAGIC; sb->s_op = &nfs_sops; sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); sb->u.nfs_sb.s_root = data->root; server = &sb->u.nfs_sb.s_server; server->rsize = nfs_block_size(data->rsize, NULL); server->wsize = nfs_block_size(data->wsize, NULL); server->flags = data->flags; if (data->flags & NFS_MOUNT_NOAC) { data->acregmin = data->acregmax = 0; data->acdirmin = data->acdirmax = 0; } server->acregmin = data->acregmin*HZ; server->acregmax = data->acregmax*HZ; server->acdirmin = data->acdirmin*HZ; server->acdirmax = data->acdirmax*HZ; server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL); if (!server->hostname) goto out_unlock; strcpy(server->hostname, data->hostname); /* Which protocol do we use? */ tcp = (data->flags & NFS_MOUNT_TCP); /* Initialize timeout values */ timeparms.to_initval = data->timeo * HZ / 10; timeparms.to_retries = data->retrans; timeparms.to_maxval = tcp? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT; timeparms.to_exponential = 1; /* Now create transport and client */ xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP, &srvaddr, &timeparms); if (xprt == NULL) goto out_no_xprt; /* Choose authentication flavor */ authflavor = RPC_AUTH_UNIX; if (data->flags & NFS_MOUNT_SECURE) authflavor = RPC_AUTH_DES; else if (data->flags & NFS_MOUNT_KERBEROS) authflavor = RPC_AUTH_KRB; clnt = rpc_create_client(xprt, server->hostname, &nfs_program, NFS_VERSION, authflavor); if (clnt == NULL) goto out_no_client; clnt->cl_intr = (data->flags & NFS_MOUNT_INTR)? 1 : 0; clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0; clnt->cl_chatty = 1; server->client = clnt; /* Fire up rpciod if not yet running */ if (rpciod_up() != 0) goto out_no_iod; /* * Keep the super block locked while we try to get * the root fh attributes. */ root_fh = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL); if (!root_fh) goto out_no_fh; *root_fh = data->root; if (nfs_proc_getattr(server, root_fh, &fattr) != 0) goto out_no_fattr; clnt->cl_to_err = 1; root_inode = __nfs_fhget(sb, &fattr); if (!root_inode) goto out_no_root; sb->s_root = d_alloc_root(root_inode, NULL); if (!sb->s_root) goto out_no_root; sb->s_root->d_op = &nfs_dentry_operations; sb->s_root->d_fsdata = root_fh; /* We're airborne */ unlock_super(sb); /* Check whether to start the lockd process */ if (!(server->flags & NFS_MOUNT_NONLM)) lockd_up(); return sb; /* Yargs. It didn't work out. */ out_no_root: printk("nfs_read_super: get root inode failed\n"); iput(root_inode); goto out_free_fh; out_no_fattr: printk("nfs_read_super: get root fattr failed\n"); out_free_fh: kfree(root_fh); out_no_fh: rpciod_down(); goto out_shutdown; out_no_iod: printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); out_shutdown: rpc_shutdown_client(server->client); goto out_free_host; out_no_client: printk(KERN_WARNING "NFS: cannot create RPC client.\n"); xprt_destroy(xprt); goto out_free_host; out_no_xprt: printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); out_free_host: kfree(server->hostname); out_unlock: unlock_super(sb); goto out_fail; out_no_remote: printk("NFS: mount program didn't pass remote address!\n"); goto out_fail; out_miss_args: printk("nfs_read_super: missing data argument\n"); out_fail: sb->s_dev = 0; MOD_DEC_USE_COUNT; return NULL; }
/* * This is the NFS server kernel thread */ static void nfsd(struct svc_rqst *rqstp) { struct svc_serv *serv = rqstp->rq_server; struct fs_struct *fsp; int err; struct nfsd_list me; sigset_t shutdown_mask, allowed_mask; /* Lock module and set up kernel thread */ lock_kernel(); daemonize("nfsd"); current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; /* After daemonize() this kernel thread shares current->fs * with the init process. We need to create files with a * umask of 0 instead of init's umask. */ fsp = copy_fs_struct(current->fs); if (!fsp) { printk("Unable to start nfsd thread: out of memory\n"); goto out; } exit_fs(current); current->fs = fsp; current->fs->umask = 0; siginitsetinv(&shutdown_mask, SHUTDOWN_SIGS); siginitsetinv(&allowed_mask, ALLOWED_SIGS); nfsdstats.th_cnt++; lockd_up(); /* start lockd */ me.task = current; list_add(&me.list, &nfsd_list); unlock_kernel(); /* * We want less throttling in balance_dirty_pages() so that nfs to * localhost doesn't cause nfsd to lock up due to all the client's * dirty pages. */ current->flags |= PF_LESS_THROTTLE; /* * The main request loop */ for (;;) { /* Block all but the shutdown signals */ sigprocmask(SIG_SETMASK, &shutdown_mask, NULL); /* * Find a socket with data available and call its * recvfrom routine. */ while ((err = svc_recv(serv, rqstp, 60*60*HZ)) == -EAGAIN) ; if (err < 0) break; update_thread_usage(atomic_read(&nfsd_busy)); atomic_inc(&nfsd_busy); /* Lock the export hash tables for reading. */ exp_readlock(); /* Process request with signals blocked. */ sigprocmask(SIG_SETMASK, &allowed_mask, NULL); svc_process(serv, rqstp); /* Unlock export hash tables */ exp_readunlock(); update_thread_usage(atomic_read(&nfsd_busy)); atomic_dec(&nfsd_busy); } if (err != -EINTR) { printk(KERN_WARNING "nfsd: terminating on error %d\n", -err); } else { unsigned int signo; for (signo = 1; signo <= _NSIG; signo++) if (sigismember(¤t->pending.signal, signo) && !sigismember(¤t->blocked, signo)) break; err = signo; } lock_kernel(); /* Release lockd */ lockd_down(); /* Check if this is last thread */ if (serv->sv_nrthreads==1) { printk(KERN_WARNING "nfsd: last server has exited\n"); if (err != SIG_NOCLEAN) { printk(KERN_WARNING "nfsd: unexporting all filesystems\n"); nfsd_export_flush(); } nfsd_serv = NULL; nfsd_racache_shutdown(); /* release read-ahead cache */ nfs4_state_shutdown(); } list_del(&me.list); nfsdstats.th_cnt --; out: /* Release the thread */ svc_exit_thread(rqstp); /* Release module */ module_put_and_exit(0); }