X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=fs%2Fnfsd%2Fnfssvc.c;h=f1314c63e823d838a65863be54e0dd6bf089e190;hb=6fb2b47fa16c81317ec282248e6cff521cca31c2;hp=1d163b6169151ce870c911dc1c7eb0eb40c80a74;hpb=3fb803a990cd17546bd89c38e0e29a891f71ce7d;p=deliverable%2Flinux.git diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 1d163b616915..f1314c63e823 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -8,7 +8,6 @@ * Copyright (C) 1995, 1996, 1997 Olaf Kirch */ -#include #include #include @@ -72,7 +71,7 @@ static struct svc_version * nfsd_acl_version[] = { }; #define NFSD_ACL_MINVERS 2 -#define NFSD_ACL_NRVERS (sizeof(nfsd_acl_version)/sizeof(nfsd_acl_version[0])) +#define NFSD_ACL_NRVERS ARRAY_SIZE(nfsd_acl_version) static struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS]; static struct svc_program nfsd_acl_program = { @@ -101,7 +100,7 @@ static struct svc_version * nfsd_version[] = { }; #define NFSD_MINVERS 2 -#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) +#define NFSD_NRVERS ARRAY_SIZE(nfsd_version) static struct svc_version *nfsd_versions[NFSD_NRVERS]; struct svc_program nfsd_program = { @@ -118,6 +117,32 @@ struct svc_program nfsd_program = { }; +int nfsd_vers(int vers, enum vers_op change) +{ + if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS) + return -1; + switch(change) { + case NFSD_SET: + nfsd_versions[vers] = nfsd_version[vers]; + break; +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) + if (vers < NFSD_ACL_NRVERS) + nfsd_acl_version[vers] = nfsd_acl_version[vers]; +#endif + case NFSD_CLEAR: + nfsd_versions[vers] = NULL; +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) + if (vers < NFSD_ACL_NRVERS) + nfsd_acl_version[vers] = NULL; +#endif + break; + case NFSD_TEST: + return nfsd_versions[vers] != NULL; + case NFSD_AVAIL: + return nfsd_version[vers] != NULL; + } + return 0; +} /* * Maximum number of nfsd processes */ @@ -131,16 +156,97 @@ int nfsd_nrthreads(void) return nfsd_serv->sv_nrthreads; } +static int killsig; /* signal that was used to kill last nfsd */ +static void nfsd_last_thread(struct svc_serv *serv) +{ + /* When last nfsd thread exits we need to do some clean-up */ + struct svc_sock *svsk; + list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) + lockd_down(); + nfsd_serv = NULL; + nfsd_racache_shutdown(); + nfs4_state_shutdown(); + + printk(KERN_WARNING "nfsd: last server has exited\n"); + if (killsig != SIG_NOCLEAN) { + printk(KERN_WARNING "nfsd: unexporting all filesystems\n"); + nfsd_export_flush(); + } +} + +void nfsd_reset_versions(void) +{ + int found_one = 0; + int i; + + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { + if (nfsd_program.pg_vers[i]) + found_one = 1; + } + + if (!found_one) { + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) + nfsd_program.pg_vers[i] = nfsd_version[i]; +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) + for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) + nfsd_acl_program.pg_vers[i] = + nfsd_acl_version[i]; +#endif + } +} + +int nfsd_create_serv(void) +{ + int err = 0; + lock_kernel(); + if (nfsd_serv) { + nfsd_serv->sv_nrthreads++; + unlock_kernel(); + return 0; + } + + atomic_set(&nfsd_busy, 0); + nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE, + nfsd_last_thread); + if (nfsd_serv == NULL) + err = -ENOMEM; + unlock_kernel(); + do_gettimeofday(&nfssvc_boot); /* record boot time */ + return err; +} + +static int nfsd_init_socks(int port) +{ + int error; + if (!list_empty(&nfsd_serv->sv_permsocks)) + return 0; + + error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); + if (error < 0) + return error; + error = lockd_up(IPPROTO_UDP); + if (error < 0) + return error; + +#ifdef CONFIG_NFSD_TCP + error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); + if (error < 0) + return error; + error = lockd_up(IPPROTO_TCP); + if (error < 0) + return error; +#endif + return 0; +} + int nfsd_svc(unsigned short port, int nrservs) { int error; - int none_left, found_one, i; struct list_head *victim; lock_kernel(); - dprintk("nfsd: creating service: vers 0x%x\n", - nfsd_versbits); + dprintk("nfsd: creating service\n"); error = -EINVAL; if (nrservs <= 0) nrservs = 0; @@ -154,65 +260,17 @@ nfsd_svc(unsigned short port, int nrservs) error = nfs4_state_start(); if (error<0) goto out; - if (!nfsd_serv) { - /* - * Use the nfsd_ctlbits to define which - * versions that will be advertised. - * If nfsd_ctlbits doesn't list any version, - * export them all. - */ - found_one = 0; - - for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { - if (NFSCTL_VERISSET(nfsd_versbits, i)) { - nfsd_program.pg_vers[i] = nfsd_version[i]; - found_one = 1; - } else - nfsd_program.pg_vers[i] = NULL; - } - - if (!found_one) { - for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) - nfsd_program.pg_vers[i] = nfsd_version[i]; - } + nfsd_reset_versions(); -#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) - found_one = 0; - - for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) { - if (NFSCTL_VERISSET(nfsd_versbits, i)) { - nfsd_acl_program.pg_vers[i] = - nfsd_acl_version[i]; - found_one = 1; - } else - nfsd_acl_program.pg_vers[i] = NULL; - } + error = nfsd_create_serv(); - if (!found_one) { - for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) - nfsd_acl_program.pg_vers[i] = - nfsd_acl_version[i]; - } -#endif - - atomic_set(&nfsd_busy, 0); - error = -ENOMEM; - nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE); - if (nfsd_serv == NULL) - goto out; - error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); - if (error < 0) - goto failure; + if (error) + goto out; + error = nfsd_init_socks(port); + if (error) + goto failure; -#ifdef CONFIG_NFSD_TCP - error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); - if (error < 0) - goto failure; -#endif - do_gettimeofday(&nfssvc_boot); /* record boot time */ - } else - nfsd_serv->sv_nrthreads++; nrservs -= (nfsd_serv->sv_nrthreads-1); while (nrservs > 0) { nrservs--; @@ -232,13 +290,7 @@ nfsd_svc(unsigned short port, int nrservs) nrservs++; } failure: - none_left = (nfsd_serv->sv_nrthreads == 1); svc_destroy(nfsd_serv); /* Release server */ - if (none_left) { - nfsd_serv = NULL; - nfsd_racache_shutdown(); - nfs4_state_shutdown(); - } out: unlock_kernel(); return error; @@ -271,7 +323,6 @@ update_thread_usage(int busy_threads) static void nfsd(struct svc_rqst *rqstp) { - struct svc_serv *serv = rqstp->rq_server; struct fs_struct *fsp; int err; struct nfsd_list me; @@ -298,8 +349,6 @@ nfsd(struct svc_rqst *rqstp) nfsdstats.th_cnt++; - lockd_up(); /* start lockd */ - me.task = current; list_add(&me.list, &nfsd_list); @@ -323,8 +372,7 @@ nfsd(struct svc_rqst *rqstp) * Find a socket with data available and call its * recvfrom routine. */ - while ((err = svc_recv(serv, rqstp, - 60*60*HZ)) == -EAGAIN) + while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN) ; if (err < 0) break; @@ -337,7 +385,7 @@ nfsd(struct svc_rqst *rqstp) /* Process request with signals blocked. */ sigprocmask(SIG_SETMASK, &allowed_mask, NULL); - svc_process(serv, rqstp); + svc_process(rqstp); /* Unlock export hash tables */ exp_readunlock(); @@ -354,28 +402,13 @@ nfsd(struct svc_rqst *rqstp) if (sigismember(¤t->pending.signal, signo) && !sigismember(¤t->blocked, signo)) break; - err = signo; + killsig = signo; } - /* Clear signals before calling lockd_down() and svc_exit_thread() */ + /* Clear signals before calling svc_exit_thread() */ flush_signals(current); 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 --;