Merge branch 'for-3.5-take-2' of git://linux-nfs.org/~bfields/linux

Pull nfsd update from Bruce Fields.

* 'for-3.5-take-2' of git://linux-nfs.org/~bfields/linux: (23 commits)
  nfsd: trivial: use SEEK_SET instead of 0 in vfs_llseek
  SUNRPC: split upcall function to extract reusable parts
  nfsd: allocate id-to-name and name-to-id caches in per-net operations.
  nfsd: make name-to-id cache allocated per network namespace context
  nfsd: make id-to-name cache allocated per network namespace context
  nfsd: pass network context to idmap init/exit functions
  nfsd: allocate export and expkey caches in per-net operations.
  nfsd: make expkey cache allocated per network namespace context
  nfsd: make export cache allocated per network namespace context
  nfsd: pass pointer to export cache down to stack wherever possible.
  nfsd: pass network context to export caches init/shutdown routines
  Lockd: pass network namespace to creation and destruction routines
  NFSd: remove hard-coded dereferences to name-to-id and id-to-name caches
  nfsd: pass pointer to expkey cache down to stack wherever possible.
  nfsd: use hash table from cache detail in nfsd export seq ops
  nfsd: pass svc_export_cache pointer as private data to "exports" seq file ops
  nfsd: use exp_put() for svc_export_cache put
  nfsd: use cache detail pointer from svc_export structure on cache put
  nfsd: add link to owner cache detail to svc_export structure
  nfsd: use passed cache_detail pointer expkey_parse()
  ...
This commit is contained in:
Linus Torvalds 2012-05-31 18:18:11 -07:00
commit a00b6151a2
16 changed files with 327 additions and 214 deletions

View file

@ -56,7 +56,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4; u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
int status; int status;
status = lockd_up(); status = lockd_up(nlm_init->net);
if (status < 0) if (status < 0)
return ERR_PTR(status); return ERR_PTR(status);
@ -65,7 +65,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
nlm_init->hostname, nlm_init->noresvport, nlm_init->hostname, nlm_init->noresvport,
nlm_init->net); nlm_init->net);
if (host == NULL) { if (host == NULL) {
lockd_down(); lockd_down(nlm_init->net);
return ERR_PTR(-ENOLCK); return ERR_PTR(-ENOLCK);
} }
@ -80,8 +80,10 @@ EXPORT_SYMBOL_GPL(nlmclnt_init);
*/ */
void nlmclnt_done(struct nlm_host *host) void nlmclnt_done(struct nlm_host *host)
{ {
struct net *net = host->net;
nlmclnt_release_host(host); nlmclnt_release_host(host);
lockd_down(); lockd_down(net);
} }
EXPORT_SYMBOL_GPL(nlmclnt_done); EXPORT_SYMBOL_GPL(nlmclnt_done);
@ -220,11 +222,12 @@ reclaimer(void *ptr)
struct nlm_wait *block; struct nlm_wait *block;
struct file_lock *fl, *next; struct file_lock *fl, *next;
u32 nsmstate; u32 nsmstate;
struct net *net = host->net;
allow_signal(SIGKILL); allow_signal(SIGKILL);
down_write(&host->h_rwsem); down_write(&host->h_rwsem);
lockd_up(); /* note: this cannot fail as lockd is already running */ lockd_up(net); /* note: this cannot fail as lockd is already running */
dprintk("lockd: reclaiming locks for host %s\n", host->h_name); dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
@ -275,6 +278,6 @@ restart:
/* Release host handle after use */ /* Release host handle after use */
nlmclnt_release_host(host); nlmclnt_release_host(host);
lockd_down(); lockd_down(net);
return 0; return 0;
} }

View file

@ -295,11 +295,10 @@ static void lockd_down_net(struct net *net)
/* /*
* Bring up the lockd process if it's not already up. * Bring up the lockd process if it's not already up.
*/ */
int lockd_up(void) int lockd_up(struct net *net)
{ {
struct svc_serv *serv; struct svc_serv *serv;
int error = 0; int error = 0;
struct net *net = current->nsproxy->net_ns;
mutex_lock(&nlmsvc_mutex); mutex_lock(&nlmsvc_mutex);
/* /*
@ -378,12 +377,12 @@ EXPORT_SYMBOL_GPL(lockd_up);
* Decrement the user count and bring down lockd if we're the last. * Decrement the user count and bring down lockd if we're the last.
*/ */
void void
lockd_down(void) lockd_down(struct net *net)
{ {
mutex_lock(&nlmsvc_mutex); mutex_lock(&nlmsvc_mutex);
if (nlmsvc_users) { if (nlmsvc_users) {
if (--nlmsvc_users) { if (--nlmsvc_users) {
lockd_down_net(current->nsproxy->net_ns); lockd_down_net(net);
goto out; goto out;
} }
} else { } else {

View file

@ -15,11 +15,13 @@
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/exportfs.h> #include <linux/exportfs.h>
#include <linux/sunrpc/svc_xprt.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include "nfsd.h" #include "nfsd.h"
#include "nfsfh.h" #include "nfsfh.h"
#include "netns.h"
#define NFSDDBG_FACILITY NFSDDBG_EXPORT #define NFSDDBG_FACILITY NFSDDBG_EXPORT
@ -38,7 +40,6 @@ typedef struct svc_export svc_export;
#define EXPKEY_HASHBITS 8 #define EXPKEY_HASHBITS 8
#define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS) #define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS)
#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
static struct cache_head *expkey_table[EXPKEY_HASHMAX];
static void expkey_put(struct kref *ref) static void expkey_put(struct kref *ref)
{ {
@ -71,9 +72,9 @@ static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
return sunrpc_cache_pipe_upcall(cd, h, expkey_request); return sunrpc_cache_pipe_upcall(cd, h, expkey_request);
} }
static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); static struct svc_expkey *svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); struct svc_expkey *old);
static struct cache_detail svc_expkey_cache; static struct svc_expkey *svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *);
static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
{ {
@ -131,7 +132,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
key.ek_fsidtype = fsidtype; key.ek_fsidtype = fsidtype;
memcpy(key.ek_fsid, buf, len); memcpy(key.ek_fsid, buf, len);
ek = svc_expkey_lookup(&key); ek = svc_expkey_lookup(cd, &key);
err = -ENOMEM; err = -ENOMEM;
if (!ek) if (!ek)
goto out; goto out;
@ -145,7 +146,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
err = 0; err = 0;
if (len == 0) { if (len == 0) {
set_bit(CACHE_NEGATIVE, &key.h.flags); set_bit(CACHE_NEGATIVE, &key.h.flags);
ek = svc_expkey_update(&key, ek); ek = svc_expkey_update(cd, &key, ek);
if (!ek) if (!ek)
err = -ENOMEM; err = -ENOMEM;
} else { } else {
@ -155,7 +156,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
dprintk("Found the path %s\n", buf); dprintk("Found the path %s\n", buf);
ek = svc_expkey_update(&key, ek); ek = svc_expkey_update(cd, &key, ek);
if (!ek) if (!ek)
err = -ENOMEM; err = -ENOMEM;
path_put(&key.ek_path); path_put(&key.ek_path);
@ -163,7 +164,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
cache_flush(); cache_flush();
out: out:
if (ek) if (ek)
cache_put(&ek->h, &svc_expkey_cache); cache_put(&ek->h, cd);
if (dom) if (dom)
auth_domain_put(dom); auth_domain_put(dom);
kfree(buf); kfree(buf);
@ -239,10 +240,9 @@ static struct cache_head *expkey_alloc(void)
return NULL; return NULL;
} }
static struct cache_detail svc_expkey_cache = { static struct cache_detail svc_expkey_cache_template = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hash_size = EXPKEY_HASHMAX, .hash_size = EXPKEY_HASHMAX,
.hash_table = expkey_table,
.name = "nfsd.fh", .name = "nfsd.fh",
.cache_put = expkey_put, .cache_put = expkey_put,
.cache_upcall = expkey_upcall, .cache_upcall = expkey_upcall,
@ -268,13 +268,12 @@ svc_expkey_hash(struct svc_expkey *item)
} }
static struct svc_expkey * static struct svc_expkey *
svc_expkey_lookup(struct svc_expkey *item) svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *item)
{ {
struct cache_head *ch; struct cache_head *ch;
int hash = svc_expkey_hash(item); int hash = svc_expkey_hash(item);
ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h, ch = sunrpc_cache_lookup(cd, &item->h, hash);
hash);
if (ch) if (ch)
return container_of(ch, struct svc_expkey, h); return container_of(ch, struct svc_expkey, h);
else else
@ -282,13 +281,13 @@ svc_expkey_lookup(struct svc_expkey *item)
} }
static struct svc_expkey * static struct svc_expkey *
svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
struct svc_expkey *old)
{ {
struct cache_head *ch; struct cache_head *ch;
int hash = svc_expkey_hash(new); int hash = svc_expkey_hash(new);
ch = sunrpc_cache_update(&svc_expkey_cache, &new->h, ch = sunrpc_cache_update(cd, &new->h, &old->h, hash);
&old->h, hash);
if (ch) if (ch)
return container_of(ch, struct svc_expkey, h); return container_of(ch, struct svc_expkey, h);
else else
@ -299,8 +298,6 @@ svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
#define EXPORT_HASHBITS 8 #define EXPORT_HASHBITS 8
#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
static struct cache_head *export_table[EXPORT_HASHMAX];
static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc) static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
{ {
int i; int i;
@ -525,6 +522,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
goto out1; goto out1;
exp.ex_client = dom; exp.ex_client = dom;
exp.cd = cd;
/* expiry */ /* expiry */
err = -EINVAL; err = -EINVAL;
@ -672,6 +670,7 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
new->ex_fslocs.locations = NULL; new->ex_fslocs.locations = NULL;
new->ex_fslocs.locations_count = 0; new->ex_fslocs.locations_count = 0;
new->ex_fslocs.migrated = 0; new->ex_fslocs.migrated = 0;
new->cd = item->cd;
} }
static void export_update(struct cache_head *cnew, struct cache_head *citem) static void export_update(struct cache_head *cnew, struct cache_head *citem)
@ -707,10 +706,9 @@ static struct cache_head *svc_export_alloc(void)
return NULL; return NULL;
} }
struct cache_detail svc_export_cache = { struct cache_detail svc_export_cache_template = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hash_size = EXPORT_HASHMAX, .hash_size = EXPORT_HASHMAX,
.hash_table = export_table,
.name = "nfsd.export", .name = "nfsd.export",
.cache_put = svc_export_put, .cache_put = svc_export_put,
.cache_upcall = svc_export_upcall, .cache_upcall = svc_export_upcall,
@ -739,8 +737,7 @@ svc_export_lookup(struct svc_export *exp)
struct cache_head *ch; struct cache_head *ch;
int hash = svc_export_hash(exp); int hash = svc_export_hash(exp);
ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h, ch = sunrpc_cache_lookup(exp->cd, &exp->h, hash);
hash);
if (ch) if (ch)
return container_of(ch, struct svc_export, h); return container_of(ch, struct svc_export, h);
else else
@ -753,9 +750,7 @@ svc_export_update(struct svc_export *new, struct svc_export *old)
struct cache_head *ch; struct cache_head *ch;
int hash = svc_export_hash(old); int hash = svc_export_hash(old);
ch = sunrpc_cache_update(&svc_export_cache, &new->h, ch = sunrpc_cache_update(old->cd, &new->h, &old->h, hash);
&old->h,
hash);
if (ch) if (ch)
return container_of(ch, struct svc_export, h); return container_of(ch, struct svc_export, h);
else else
@ -764,7 +759,8 @@ svc_export_update(struct svc_export *new, struct svc_export *old)
static struct svc_expkey * static struct svc_expkey *
exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) exp_find_key(struct cache_detail *cd, svc_client *clp, int fsid_type,
u32 *fsidv, struct cache_req *reqp)
{ {
struct svc_expkey key, *ek; struct svc_expkey key, *ek;
int err; int err;
@ -776,18 +772,18 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
key.ek_fsidtype = fsid_type; key.ek_fsidtype = fsid_type;
memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
ek = svc_expkey_lookup(&key); ek = svc_expkey_lookup(cd, &key);
if (ek == NULL) if (ek == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
err = cache_check(&svc_expkey_cache, &ek->h, reqp); err = cache_check(cd, &ek->h, reqp);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
return ek; return ek;
} }
static svc_export *exp_get_by_name(svc_client *clp, const struct path *path, static svc_export *exp_get_by_name(struct cache_detail *cd, svc_client *clp,
struct cache_req *reqp) const struct path *path, struct cache_req *reqp)
{ {
struct svc_export *exp, key; struct svc_export *exp, key;
int err; int err;
@ -797,11 +793,12 @@ static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
key.ex_client = clp; key.ex_client = clp;
key.ex_path = *path; key.ex_path = *path;
key.cd = cd;
exp = svc_export_lookup(&key); exp = svc_export_lookup(&key);
if (exp == NULL) if (exp == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
err = cache_check(&svc_export_cache, &exp->h, reqp); err = cache_check(cd, &exp->h, reqp);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
return exp; return exp;
@ -810,16 +807,17 @@ static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
/* /*
* Find the export entry for a given dentry. * Find the export entry for a given dentry.
*/ */
static struct svc_export *exp_parent(svc_client *clp, struct path *path) static struct svc_export *exp_parent(struct cache_detail *cd, svc_client *clp,
struct path *path)
{ {
struct dentry *saved = dget(path->dentry); struct dentry *saved = dget(path->dentry);
svc_export *exp = exp_get_by_name(clp, path, NULL); svc_export *exp = exp_get_by_name(cd, clp, path, NULL);
while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) { while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
struct dentry *parent = dget_parent(path->dentry); struct dentry *parent = dget_parent(path->dentry);
dput(path->dentry); dput(path->dentry);
path->dentry = parent; path->dentry = parent;
exp = exp_get_by_name(clp, path, NULL); exp = exp_get_by_name(cd, clp, path, NULL);
} }
dput(path->dentry); dput(path->dentry);
path->dentry = saved; path->dentry = saved;
@ -834,13 +832,16 @@ static struct svc_export *exp_parent(svc_client *clp, struct path *path)
* since its harder to fool a kernel module than a user space program. * since its harder to fool a kernel module than a user space program.
*/ */
int int
exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize) exp_rootfh(struct net *net, svc_client *clp, char *name,
struct knfsd_fh *f, int maxsize)
{ {
struct svc_export *exp; struct svc_export *exp;
struct path path; struct path path;
struct inode *inode; struct inode *inode;
struct svc_fh fh; struct svc_fh fh;
int err; int err;
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
struct cache_detail *cd = nn->svc_export_cache;
err = -EPERM; err = -EPERM;
/* NB: we probably ought to check that it's NUL-terminated */ /* NB: we probably ought to check that it's NUL-terminated */
@ -853,7 +854,7 @@ exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
name, path.dentry, clp->name, name, path.dentry, clp->name,
inode->i_sb->s_id, inode->i_ino); inode->i_sb->s_id, inode->i_ino);
exp = exp_parent(clp, &path); exp = exp_parent(cd, clp, &path);
if (IS_ERR(exp)) { if (IS_ERR(exp)) {
err = PTR_ERR(exp); err = PTR_ERR(exp);
goto out; goto out;
@ -875,16 +876,18 @@ out:
return err; return err;
} }
static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type, static struct svc_export *exp_find(struct cache_detail *cd,
struct auth_domain *clp, int fsid_type,
u32 *fsidv, struct cache_req *reqp) u32 *fsidv, struct cache_req *reqp)
{ {
struct svc_export *exp; struct svc_export *exp;
struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); struct nfsd_net *nn = net_generic(cd->net, nfsd_net_id);
struct svc_expkey *ek = exp_find_key(nn->svc_expkey_cache, clp, fsid_type, fsidv, reqp);
if (IS_ERR(ek)) if (IS_ERR(ek))
return ERR_CAST(ek); return ERR_CAST(ek);
exp = exp_get_by_name(clp, &ek->ek_path, reqp); exp = exp_get_by_name(cd, clp, &ek->ek_path, reqp);
cache_put(&ek->h, &svc_expkey_cache); cache_put(&ek->h, nn->svc_expkey_cache);
if (IS_ERR(exp)) if (IS_ERR(exp))
return ERR_CAST(exp); return ERR_CAST(exp);
@ -926,12 +929,14 @@ struct svc_export *
rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path) rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
{ {
struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
struct cache_detail *cd = nn->svc_export_cache;
if (rqstp->rq_client == NULL) if (rqstp->rq_client == NULL)
goto gss; goto gss;
/* First try the auth_unix client: */ /* First try the auth_unix client: */
exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle); exp = exp_get_by_name(cd, rqstp->rq_client, path, &rqstp->rq_chandle);
if (PTR_ERR(exp) == -ENOENT) if (PTR_ERR(exp) == -ENOENT)
goto gss; goto gss;
if (IS_ERR(exp)) if (IS_ERR(exp))
@ -943,7 +948,7 @@ gss:
/* Otherwise, try falling back on gss client */ /* Otherwise, try falling back on gss client */
if (rqstp->rq_gssclient == NULL) if (rqstp->rq_gssclient == NULL)
return exp; return exp;
gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle); gssexp = exp_get_by_name(cd, rqstp->rq_gssclient, path, &rqstp->rq_chandle);
if (PTR_ERR(gssexp) == -ENOENT) if (PTR_ERR(gssexp) == -ENOENT)
return exp; return exp;
if (!IS_ERR(exp)) if (!IS_ERR(exp))
@ -955,12 +960,15 @@ struct svc_export *
rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv) rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
{ {
struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
struct cache_detail *cd = nn->svc_export_cache;
if (rqstp->rq_client == NULL) if (rqstp->rq_client == NULL)
goto gss; goto gss;
/* First try the auth_unix client: */ /* First try the auth_unix client: */
exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle); exp = exp_find(cd, rqstp->rq_client, fsid_type,
fsidv, &rqstp->rq_chandle);
if (PTR_ERR(exp) == -ENOENT) if (PTR_ERR(exp) == -ENOENT)
goto gss; goto gss;
if (IS_ERR(exp)) if (IS_ERR(exp))
@ -972,7 +980,7 @@ gss:
/* Otherwise, try falling back on gss client */ /* Otherwise, try falling back on gss client */
if (rqstp->rq_gssclient == NULL) if (rqstp->rq_gssclient == NULL)
return exp; return exp;
gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv, gssexp = exp_find(cd, rqstp->rq_gssclient, fsid_type, fsidv,
&rqstp->rq_chandle); &rqstp->rq_chandle);
if (PTR_ERR(gssexp) == -ENOENT) if (PTR_ERR(gssexp) == -ENOENT)
return exp; return exp;
@ -1029,13 +1037,15 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
/* Iterator */ /* Iterator */
static void *e_start(struct seq_file *m, loff_t *pos) static void *e_start(struct seq_file *m, loff_t *pos)
__acquires(svc_export_cache.hash_lock) __acquires(((struct cache_detail *)m->private)->hash_lock)
{ {
loff_t n = *pos; loff_t n = *pos;
unsigned hash, export; unsigned hash, export;
struct cache_head *ch; struct cache_head *ch;
struct cache_detail *cd = m->private;
read_lock(&svc_export_cache.hash_lock); struct cache_head **export_table = cd->hash_table;
read_lock(&cd->hash_lock);
if (!n--) if (!n--)
return SEQ_START_TOKEN; return SEQ_START_TOKEN;
hash = n >> 32; hash = n >> 32;
@ -1060,6 +1070,8 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos)
{ {
struct cache_head *ch = p; struct cache_head *ch = p;
int hash = (*pos >> 32); int hash = (*pos >> 32);
struct cache_detail *cd = m->private;
struct cache_head **export_table = cd->hash_table;
if (p == SEQ_START_TOKEN) if (p == SEQ_START_TOKEN)
hash = 0; hash = 0;
@ -1082,9 +1094,11 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos)
} }
static void e_stop(struct seq_file *m, void *p) static void e_stop(struct seq_file *m, void *p)
__releases(svc_export_cache.hash_lock) __releases(((struct cache_detail *)m->private)->hash_lock)
{ {
read_unlock(&svc_export_cache.hash_lock); struct cache_detail *cd = m->private;
read_unlock(&cd->hash_lock);
} }
static struct flags { static struct flags {
@ -1195,6 +1209,7 @@ static int e_show(struct seq_file *m, void *p)
{ {
struct cache_head *cp = p; struct cache_head *cp = p;
struct svc_export *exp = container_of(cp, struct svc_export, h); struct svc_export *exp = container_of(cp, struct svc_export, h);
struct cache_detail *cd = m->private;
if (p == SEQ_START_TOKEN) { if (p == SEQ_START_TOKEN) {
seq_puts(m, "# Version 1.1\n"); seq_puts(m, "# Version 1.1\n");
@ -1203,10 +1218,10 @@ static int e_show(struct seq_file *m, void *p)
} }
cache_get(&exp->h); cache_get(&exp->h);
if (cache_check(&svc_export_cache, &exp->h, NULL)) if (cache_check(cd, &exp->h, NULL))
return 0; return 0;
cache_put(&exp->h, &svc_export_cache); exp_put(exp);
return svc_export_show(m, &svc_export_cache, cp); return svc_export_show(m, cd, cp);
} }
const struct seq_operations nfs_exports_op = { const struct seq_operations nfs_exports_op = {
@ -1216,48 +1231,70 @@ const struct seq_operations nfs_exports_op = {
.show = e_show, .show = e_show,
}; };
/* /*
* Initialize the exports module. * Initialize the exports module.
*/ */
int int
nfsd_export_init(void) nfsd_export_init(struct net *net)
{ {
int rv; int rv;
dprintk("nfsd: initializing export module.\n"); struct nfsd_net *nn = net_generic(net, nfsd_net_id);
rv = cache_register_net(&svc_export_cache, &init_net); dprintk("nfsd: initializing export module (net: %p).\n", net);
nn->svc_export_cache = cache_create_net(&svc_export_cache_template, net);
if (IS_ERR(nn->svc_export_cache))
return PTR_ERR(nn->svc_export_cache);
rv = cache_register_net(nn->svc_export_cache, net);
if (rv) if (rv)
return rv; goto destroy_export_cache;
rv = cache_register_net(&svc_expkey_cache, &init_net);
nn->svc_expkey_cache = cache_create_net(&svc_expkey_cache_template, net);
if (IS_ERR(nn->svc_expkey_cache)) {
rv = PTR_ERR(nn->svc_expkey_cache);
goto unregister_export_cache;
}
rv = cache_register_net(nn->svc_expkey_cache, net);
if (rv) if (rv)
cache_unregister_net(&svc_export_cache, &init_net); goto destroy_expkey_cache;
return 0;
destroy_expkey_cache:
cache_destroy_net(nn->svc_expkey_cache, net);
unregister_export_cache:
cache_unregister_net(nn->svc_export_cache, net);
destroy_export_cache:
cache_destroy_net(nn->svc_export_cache, net);
return rv; return rv;
} }
/* /*
* Flush exports table - called when last nfsd thread is killed * Flush exports table - called when last nfsd thread is killed
*/ */
void void
nfsd_export_flush(void) nfsd_export_flush(struct net *net)
{ {
cache_purge(&svc_expkey_cache); struct nfsd_net *nn = net_generic(net, nfsd_net_id);
cache_purge(&svc_export_cache);
cache_purge(nn->svc_expkey_cache);
cache_purge(nn->svc_export_cache);
} }
/* /*
* Shutdown the exports module. * Shutdown the exports module.
*/ */
void void
nfsd_export_shutdown(void) nfsd_export_shutdown(struct net *net)
{ {
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
dprintk("nfsd: shutting down export module.\n"); dprintk("nfsd: shutting down export module (net: %p).\n", net);
cache_unregister_net(&svc_expkey_cache, &init_net); cache_unregister_net(nn->svc_expkey_cache, net);
cache_unregister_net(&svc_export_cache, &init_net); cache_unregister_net(nn->svc_export_cache, net);
svcauth_unix_purge(); cache_destroy_net(nn->svc_expkey_cache, net);
cache_destroy_net(nn->svc_export_cache, net);
svcauth_unix_purge(net);
dprintk("nfsd: export shutdown complete.\n"); dprintk("nfsd: export shutdown complete (net: %p).\n", net);
} }

View file

@ -42,14 +42,14 @@
#define IDMAP_NAMESZ 128 #define IDMAP_NAMESZ 128
#ifdef CONFIG_NFSD_V4 #ifdef CONFIG_NFSD_V4
int nfsd_idmap_init(void); int nfsd_idmap_init(struct net *);
void nfsd_idmap_shutdown(void); void nfsd_idmap_shutdown(struct net *);
#else #else
static inline int nfsd_idmap_init(void) static inline int nfsd_idmap_init(struct net *net)
{ {
return 0; return 0;
} }
static inline void nfsd_idmap_shutdown(void) static inline void nfsd_idmap_shutdown(struct net *net)
{ {
} }
#endif #endif

View file

@ -28,6 +28,12 @@ struct cld_net;
struct nfsd_net { struct nfsd_net {
struct cld_net *cld_net; struct cld_net *cld_net;
struct cache_detail *svc_expkey_cache;
struct cache_detail *svc_export_cache;
struct cache_detail *idtoname_cache;
struct cache_detail *nametoid_cache;
}; };
extern int nfsd_net_id; extern int nfsd_net_id;

View file

@ -36,9 +36,11 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sunrpc/svc_xprt.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include "idmap.h" #include "idmap.h"
#include "nfsd.h" #include "nfsd.h"
#include "netns.h"
/* /*
* Turn off idmapping when using AUTH_SYS. * Turn off idmapping when using AUTH_SYS.
@ -107,8 +109,6 @@ ent_alloc(void)
* ID -> Name cache * ID -> Name cache
*/ */
static struct cache_head *idtoname_table[ENT_HASHMAX];
static uint32_t static uint32_t
idtoname_hash(struct ent *ent) idtoname_hash(struct ent *ent)
{ {
@ -183,13 +183,13 @@ warn_no_idmapd(struct cache_detail *detail, int has_died)
static int idtoname_parse(struct cache_detail *, char *, int); static int idtoname_parse(struct cache_detail *, char *, int);
static struct ent *idtoname_lookup(struct ent *); static struct ent *idtoname_lookup(struct cache_detail *, struct ent *);
static struct ent *idtoname_update(struct ent *, struct ent *); static struct ent *idtoname_update(struct cache_detail *, struct ent *,
struct ent *);
static struct cache_detail idtoname_cache = { static struct cache_detail idtoname_cache_template = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hash_size = ENT_HASHMAX, .hash_size = ENT_HASHMAX,
.hash_table = idtoname_table,
.name = "nfs4.idtoname", .name = "nfs4.idtoname",
.cache_put = ent_put, .cache_put = ent_put,
.cache_upcall = idtoname_upcall, .cache_upcall = idtoname_upcall,
@ -244,7 +244,7 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
goto out; goto out;
error = -ENOMEM; error = -ENOMEM;
res = idtoname_lookup(&ent); res = idtoname_lookup(cd, &ent);
if (!res) if (!res)
goto out; goto out;
@ -260,11 +260,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
else else
memcpy(ent.name, buf1, sizeof(ent.name)); memcpy(ent.name, buf1, sizeof(ent.name));
error = -ENOMEM; error = -ENOMEM;
res = idtoname_update(&ent, res); res = idtoname_update(cd, &ent, res);
if (res == NULL) if (res == NULL)
goto out; goto out;
cache_put(&res->h, &idtoname_cache); cache_put(&res->h, cd);
error = 0; error = 0;
out: out:
@ -275,10 +275,9 @@ out:
static struct ent * static struct ent *
idtoname_lookup(struct ent *item) idtoname_lookup(struct cache_detail *cd, struct ent *item)
{ {
struct cache_head *ch = sunrpc_cache_lookup(&idtoname_cache, struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h,
&item->h,
idtoname_hash(item)); idtoname_hash(item));
if (ch) if (ch)
return container_of(ch, struct ent, h); return container_of(ch, struct ent, h);
@ -287,10 +286,9 @@ idtoname_lookup(struct ent *item)
} }
static struct ent * static struct ent *
idtoname_update(struct ent *new, struct ent *old) idtoname_update(struct cache_detail *cd, struct ent *new, struct ent *old)
{ {
struct cache_head *ch = sunrpc_cache_update(&idtoname_cache, struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h,
&new->h, &old->h,
idtoname_hash(new)); idtoname_hash(new));
if (ch) if (ch)
return container_of(ch, struct ent, h); return container_of(ch, struct ent, h);
@ -303,8 +301,6 @@ idtoname_update(struct ent *new, struct ent *old)
* Name -> ID cache * Name -> ID cache
*/ */
static struct cache_head *nametoid_table[ENT_HASHMAX];
static inline int static inline int
nametoid_hash(struct ent *ent) nametoid_hash(struct ent *ent)
{ {
@ -359,14 +355,14 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
return 0; return 0;
} }
static struct ent *nametoid_lookup(struct ent *); static struct ent *nametoid_lookup(struct cache_detail *, struct ent *);
static struct ent *nametoid_update(struct ent *, struct ent *); static struct ent *nametoid_update(struct cache_detail *, struct ent *,
struct ent *);
static int nametoid_parse(struct cache_detail *, char *, int); static int nametoid_parse(struct cache_detail *, char *, int);
static struct cache_detail nametoid_cache = { static struct cache_detail nametoid_cache_template = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hash_size = ENT_HASHMAX, .hash_size = ENT_HASHMAX,
.hash_table = nametoid_table,
.name = "nfs4.nametoid", .name = "nfs4.nametoid",
.cache_put = ent_put, .cache_put = ent_put,
.cache_upcall = nametoid_upcall, .cache_upcall = nametoid_upcall,
@ -426,14 +422,14 @@ nametoid_parse(struct cache_detail *cd, char *buf, int buflen)
set_bit(CACHE_NEGATIVE, &ent.h.flags); set_bit(CACHE_NEGATIVE, &ent.h.flags);
error = -ENOMEM; error = -ENOMEM;
res = nametoid_lookup(&ent); res = nametoid_lookup(cd, &ent);
if (res == NULL) if (res == NULL)
goto out; goto out;
res = nametoid_update(&ent, res); res = nametoid_update(cd, &ent, res);
if (res == NULL) if (res == NULL)
goto out; goto out;
cache_put(&res->h, &nametoid_cache); cache_put(&res->h, cd);
error = 0; error = 0;
out: out:
kfree(buf1); kfree(buf1);
@ -443,10 +439,9 @@ out:
static struct ent * static struct ent *
nametoid_lookup(struct ent *item) nametoid_lookup(struct cache_detail *cd, struct ent *item)
{ {
struct cache_head *ch = sunrpc_cache_lookup(&nametoid_cache, struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h,
&item->h,
nametoid_hash(item)); nametoid_hash(item));
if (ch) if (ch)
return container_of(ch, struct ent, h); return container_of(ch, struct ent, h);
@ -455,10 +450,9 @@ nametoid_lookup(struct ent *item)
} }
static struct ent * static struct ent *
nametoid_update(struct ent *new, struct ent *old) nametoid_update(struct cache_detail *cd, struct ent *new, struct ent *old)
{ {
struct cache_head *ch = sunrpc_cache_update(&nametoid_cache, struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h,
&new->h, &old->h,
nametoid_hash(new)); nametoid_hash(new));
if (ch) if (ch)
return container_of(ch, struct ent, h); return container_of(ch, struct ent, h);
@ -471,34 +465,55 @@ nametoid_update(struct ent *new, struct ent *old)
*/ */
int int
nfsd_idmap_init(void) nfsd_idmap_init(struct net *net)
{ {
int rv; int rv;
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
rv = cache_register_net(&idtoname_cache, &init_net); nn->idtoname_cache = cache_create_net(&idtoname_cache_template, net);
if (IS_ERR(nn->idtoname_cache))
return PTR_ERR(nn->idtoname_cache);
rv = cache_register_net(nn->idtoname_cache, net);
if (rv) if (rv)
return rv; goto destroy_idtoname_cache;
rv = cache_register_net(&nametoid_cache, &init_net); nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net);
if (IS_ERR(nn->nametoid_cache)) {
rv = PTR_ERR(nn->idtoname_cache);
goto unregister_idtoname_cache;
}
rv = cache_register_net(nn->nametoid_cache, net);
if (rv) if (rv)
cache_unregister_net(&idtoname_cache, &init_net); goto destroy_nametoid_cache;
return 0;
destroy_nametoid_cache:
cache_destroy_net(nn->nametoid_cache, net);
unregister_idtoname_cache:
cache_unregister_net(nn->idtoname_cache, net);
destroy_idtoname_cache:
cache_destroy_net(nn->idtoname_cache, net);
return rv; return rv;
} }
void void
nfsd_idmap_shutdown(void) nfsd_idmap_shutdown(struct net *net)
{ {
cache_unregister_net(&idtoname_cache, &init_net); struct nfsd_net *nn = net_generic(net, nfsd_net_id);
cache_unregister_net(&nametoid_cache, &init_net);
cache_unregister_net(nn->idtoname_cache, net);
cache_unregister_net(nn->nametoid_cache, net);
cache_destroy_net(nn->idtoname_cache, net);
cache_destroy_net(nn->nametoid_cache, net);
} }
static int static int
idmap_lookup(struct svc_rqst *rqstp, idmap_lookup(struct svc_rqst *rqstp,
struct ent *(*lookup_fn)(struct ent *), struct ent *key, struct ent *(*lookup_fn)(struct cache_detail *, struct ent *),
struct cache_detail *detail, struct ent **item) struct ent *key, struct cache_detail *detail, struct ent **item)
{ {
int ret; int ret;
*item = lookup_fn(key); *item = lookup_fn(detail, key);
if (!*item) if (!*item)
return -ENOMEM; return -ENOMEM;
retry: retry:
@ -506,7 +521,7 @@ idmap_lookup(struct svc_rqst *rqstp,
if (ret == -ETIMEDOUT) { if (ret == -ETIMEDOUT) {
struct ent *prev_item = *item; struct ent *prev_item = *item;
*item = lookup_fn(key); *item = lookup_fn(detail, key);
if (*item != prev_item) if (*item != prev_item)
goto retry; goto retry;
cache_put(&(*item)->h, detail); cache_put(&(*item)->h, detail);
@ -531,19 +546,20 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
.type = type, .type = type,
}; };
int ret; int ret;
struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
if (namelen + 1 > sizeof(key.name)) if (namelen + 1 > sizeof(key.name))
return nfserr_badowner; return nfserr_badowner;
memcpy(key.name, name, namelen); memcpy(key.name, name, namelen);
key.name[namelen] = '\0'; key.name[namelen] = '\0';
strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); ret = idmap_lookup(rqstp, nametoid_lookup, &key, nn->nametoid_cache, &item);
if (ret == -ENOENT) if (ret == -ENOENT)
return nfserr_badowner; return nfserr_badowner;
if (ret) if (ret)
return nfserrno(ret); return nfserrno(ret);
*id = item->id; *id = item->id;
cache_put(&item->h, &nametoid_cache); cache_put(&item->h, nn->nametoid_cache);
return 0; return 0;
} }
@ -555,9 +571,10 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
.type = type, .type = type,
}; };
int ret; int ret;
struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item); ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item);
if (ret == -ENOENT) if (ret == -ENOENT)
return sprintf(name, "%u", id); return sprintf(name, "%u", id);
if (ret) if (ret)
@ -565,7 +582,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
ret = strlen(item->name); ret = strlen(item->name);
BUG_ON(ret > IDMAP_NAMESZ); BUG_ON(ret > IDMAP_NAMESZ);
memcpy(name, item->name, ret); memcpy(name, item->name, ret);
cache_put(&item->h, &idtoname_cache); cache_put(&item->h, nn->idtoname_cache);
return ret; return ret;
} }

View file

@ -3155,10 +3155,17 @@ out:
static struct lock_manager nfsd4_manager = { static struct lock_manager nfsd4_manager = {
}; };
static bool grace_ended;
static void static void
nfsd4_end_grace(void) nfsd4_end_grace(void)
{ {
/* do nothing if grace period already ended */
if (grace_ended)
return;
dprintk("NFSD: end of grace period\n"); dprintk("NFSD: end of grace period\n");
grace_ended = true;
nfsd4_record_grace_done(&init_net, boot_time); nfsd4_record_grace_done(&init_net, boot_time);
locks_end_grace(&nfsd4_manager); locks_end_grace(&nfsd4_manager);
/* /*
@ -3183,8 +3190,7 @@ nfs4_laundromat(void)
nfs4_lock_state(); nfs4_lock_state();
dprintk("NFSD: laundromat service - starting\n"); dprintk("NFSD: laundromat service - starting\n");
if (locks_in_grace()) nfsd4_end_grace();
nfsd4_end_grace();
INIT_LIST_HEAD(&reaplist); INIT_LIST_HEAD(&reaplist);
spin_lock(&client_lock); spin_lock(&client_lock);
list_for_each_safe(pos, next, &client_lru) { list_for_each_safe(pos, next, &client_lru) {
@ -4055,7 +4061,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfs4_openowner *open_sop = NULL; struct nfs4_openowner *open_sop = NULL;
struct nfs4_lockowner *lock_sop = NULL; struct nfs4_lockowner *lock_sop = NULL;
struct nfs4_ol_stateid *lock_stp; struct nfs4_ol_stateid *lock_stp;
struct nfs4_file *fp;
struct file *filp = NULL; struct file *filp = NULL;
struct file_lock file_lock; struct file_lock file_lock;
struct file_lock conflock; struct file_lock conflock;
@ -4123,7 +4128,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out; goto out;
} }
lock_sop = lockowner(lock_stp->st_stateowner); lock_sop = lockowner(lock_stp->st_stateowner);
fp = lock_stp->st_file;
lkflg = setlkflg(lock->lk_type); lkflg = setlkflg(lock->lk_type);
status = nfs4_check_openmode(lock_stp, lkflg); status = nfs4_check_openmode(lock_stp, lkflg);
@ -4715,6 +4719,7 @@ nfs4_state_start(void)
nfsd4_client_tracking_init(&init_net); nfsd4_client_tracking_init(&init_net);
boot_time = get_seconds(); boot_time = get_seconds();
locks_start_grace(&nfsd4_manager); locks_start_grace(&nfsd4_manager);
grace_ended = false;
printk(KERN_INFO "NFSD: starting %ld-second grace period\n", printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
nfsd4_grace); nfsd4_grace);
ret = set_callback_cred(); ret = set_callback_cred();

View file

@ -127,7 +127,17 @@ static const struct file_operations transaction_ops = {
static int exports_open(struct inode *inode, struct file *file) static int exports_open(struct inode *inode, struct file *file)
{ {
return seq_open(file, &nfs_exports_op); int err;
struct seq_file *seq;
struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
err = seq_open(file, &nfs_exports_op);
if (err)
return err;
seq = file->private_data;
seq->private = nn->svc_export_cache;
return 0;
} }
static const struct file_operations exports_operations = { static const struct file_operations exports_operations = {
@ -345,7 +355,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
if (!dom) if (!dom)
return -ENOMEM; return -ENOMEM;
len = exp_rootfh(dom, path, &fh, maxsize); len = exp_rootfh(&init_net, dom, path, &fh, maxsize);
auth_domain_put(dom); auth_domain_put(dom);
if (len) if (len)
return len; return len;
@ -1127,7 +1137,34 @@ static int create_proc_exports_entry(void)
#endif #endif
int nfsd_net_id; int nfsd_net_id;
static __net_init int nfsd_init_net(struct net *net)
{
int retval;
retval = nfsd_export_init(net);
if (retval)
goto out_export_error;
retval = nfsd_idmap_init(net);
if (retval)
goto out_idmap_error;
return 0;
out_idmap_error:
nfsd_export_shutdown(net);
out_export_error:
return retval;
}
static __net_exit void nfsd_exit_net(struct net *net)
{
nfsd_idmap_shutdown(net);
nfsd_export_shutdown(net);
}
static struct pernet_operations nfsd_net_ops = { static struct pernet_operations nfsd_net_ops = {
.init = nfsd_init_net,
.exit = nfsd_exit_net,
.id = &nfsd_net_id, .id = &nfsd_net_id,
.size = sizeof(struct nfsd_net), .size = sizeof(struct nfsd_net),
}; };
@ -1154,16 +1191,10 @@ static int __init init_nfsd(void)
retval = nfsd_reply_cache_init(); retval = nfsd_reply_cache_init();
if (retval) if (retval)
goto out_free_stat; goto out_free_stat;
retval = nfsd_export_init();
if (retval)
goto out_free_cache;
nfsd_lockd_init(); /* lockd->nfsd callbacks */ nfsd_lockd_init(); /* lockd->nfsd callbacks */
retval = nfsd_idmap_init();
if (retval)
goto out_free_lockd;
retval = create_proc_exports_entry(); retval = create_proc_exports_entry();
if (retval) if (retval)
goto out_free_idmap; goto out_free_lockd;
retval = register_filesystem(&nfsd_fs_type); retval = register_filesystem(&nfsd_fs_type);
if (retval) if (retval)
goto out_free_all; goto out_free_all;
@ -1171,12 +1202,8 @@ static int __init init_nfsd(void)
out_free_all: out_free_all:
remove_proc_entry("fs/nfs/exports", NULL); remove_proc_entry("fs/nfs/exports", NULL);
remove_proc_entry("fs/nfs", NULL); remove_proc_entry("fs/nfs", NULL);
out_free_idmap:
nfsd_idmap_shutdown();
out_free_lockd: out_free_lockd:
nfsd_lockd_shutdown(); nfsd_lockd_shutdown();
nfsd_export_shutdown();
out_free_cache:
nfsd_reply_cache_shutdown(); nfsd_reply_cache_shutdown();
out_free_stat: out_free_stat:
nfsd_stat_shutdown(); nfsd_stat_shutdown();
@ -1192,13 +1219,11 @@ out_unregister_notifier:
static void __exit exit_nfsd(void) static void __exit exit_nfsd(void)
{ {
nfsd_export_shutdown();
nfsd_reply_cache_shutdown(); nfsd_reply_cache_shutdown();
remove_proc_entry("fs/nfs/exports", NULL); remove_proc_entry("fs/nfs/exports", NULL);
remove_proc_entry("fs/nfs", NULL); remove_proc_entry("fs/nfs", NULL);
nfsd_stat_shutdown(); nfsd_stat_shutdown();
nfsd_lockd_shutdown(); nfsd_lockd_shutdown();
nfsd_idmap_shutdown();
nfsd4_free_slabs(); nfsd4_free_slabs();
nfsd_fault_inject_cleanup(); nfsd_fault_inject_cleanup();
unregister_filesystem(&nfsd_fs_type); unregister_filesystem(&nfsd_fs_type);

View file

@ -636,7 +636,7 @@ fh_put(struct svc_fh *fhp)
#endif #endif
} }
if (exp) { if (exp) {
cache_put(&exp->h, &svc_export_cache); exp_put(exp);
fhp->fh_export = NULL; fhp->fh_export = NULL;
} }
return; return;

View file

@ -220,7 +220,7 @@ static int nfsd_startup(unsigned short port, int nrservs)
ret = nfsd_init_socks(port); ret = nfsd_init_socks(port);
if (ret) if (ret)
goto out_racache; goto out_racache;
ret = lockd_up(); ret = lockd_up(&init_net);
if (ret) if (ret)
goto out_racache; goto out_racache;
ret = nfs4_state_start(); ret = nfs4_state_start();
@ -229,7 +229,7 @@ static int nfsd_startup(unsigned short port, int nrservs)
nfsd_up = true; nfsd_up = true;
return 0; return 0;
out_lockd: out_lockd:
lockd_down(); lockd_down(&init_net);
out_racache: out_racache:
nfsd_racache_shutdown(); nfsd_racache_shutdown();
return ret; return ret;
@ -246,7 +246,7 @@ static void nfsd_shutdown(void)
if (!nfsd_up) if (!nfsd_up)
return; return;
nfs4_state_shutdown(); nfs4_state_shutdown();
lockd_down(); lockd_down(&init_net);
nfsd_racache_shutdown(); nfsd_racache_shutdown();
nfsd_up = false; nfsd_up = false;
} }
@ -261,7 +261,7 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
printk(KERN_WARNING "nfsd: last server has exited, flushing export " printk(KERN_WARNING "nfsd: last server has exited, flushing export "
"cache\n"); "cache\n");
nfsd_export_flush(); nfsd_export_flush(net);
} }
void nfsd_reset_versions(void) void nfsd_reset_versions(void)

View file

@ -2039,7 +2039,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
if (err) if (err)
goto out; goto out;
offset = vfs_llseek(file, offset, 0); offset = vfs_llseek(file, offset, SEEK_SET);
if (offset < 0) { if (offset < 0) {
err = nfserrno((int)offset); err = nfserrno((int)offset);
goto out_close; goto out_close;

View file

@ -54,7 +54,7 @@ extern void nlmclnt_done(struct nlm_host *host);
extern int nlmclnt_proc(struct nlm_host *host, int cmd, extern int nlmclnt_proc(struct nlm_host *host, int cmd,
struct file_lock *fl); struct file_lock *fl);
extern int lockd_up(void); extern int lockd_up(struct net *net);
extern void lockd_down(void); extern void lockd_down(struct net *net);
#endif /* LINUX_LOCKD_BIND_H */ #endif /* LINUX_LOCKD_BIND_H */

View file

@ -103,6 +103,7 @@ struct svc_export {
struct nfsd4_fs_locations ex_fslocs; struct nfsd4_fs_locations ex_fslocs;
int ex_nflavors; int ex_nflavors;
struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST]; struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST];
struct cache_detail *cd;
}; };
/* an "export key" (expkey) maps a filehandlefragement to an /* an "export key" (expkey) maps a filehandlefragement to an
@ -129,24 +130,22 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
/* /*
* Function declarations * Function declarations
*/ */
int nfsd_export_init(void); int nfsd_export_init(struct net *);
void nfsd_export_shutdown(void); void nfsd_export_shutdown(struct net *);
void nfsd_export_flush(void); void nfsd_export_flush(struct net *);
struct svc_export * rqst_exp_get_by_name(struct svc_rqst *, struct svc_export * rqst_exp_get_by_name(struct svc_rqst *,
struct path *); struct path *);
struct svc_export * rqst_exp_parent(struct svc_rqst *, struct svc_export * rqst_exp_parent(struct svc_rqst *,
struct path *); struct path *);
struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *); struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *);
int exp_rootfh(struct auth_domain *, int exp_rootfh(struct net *, struct auth_domain *,
char *path, struct knfsd_fh *, int maxsize); char *path, struct knfsd_fh *, int maxsize);
__be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *); __be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *);
__be32 nfserrno(int errno); __be32 nfserrno(int errno);
extern struct cache_detail svc_export_cache;
static inline void exp_put(struct svc_export *exp) static inline void exp_put(struct svc_export *exp)
{ {
cache_put(&exp->h, &svc_export_cache); cache_put(&exp->h, exp->cd);
} }
static inline void exp_get(struct svc_export *exp) static inline void exp_get(struct svc_export *exp)

View file

@ -16,7 +16,6 @@
#include <linux/sunrpc/cache.h> #include <linux/sunrpc/cache.h>
#include <linux/hash.h> #include <linux/hash.h>
#define SVC_CRED_NGROUPS 32
struct svc_cred { struct svc_cred {
uid_t cr_uid; uid_t cr_uid;
gid_t cr_gid; gid_t cr_gid;
@ -131,7 +130,7 @@ extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *ne
extern struct auth_domain *auth_domain_find(char *name); extern struct auth_domain *auth_domain_find(char *name);
extern struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr); extern struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr);
extern int auth_unix_forget_old(struct auth_domain *dom); extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void); extern void svcauth_unix_purge(struct net *net);
extern void svcauth_unix_info_release(struct svc_xprt *xpt); extern void svcauth_unix_info_release(struct svc_xprt *xpt);
extern int svcauth_unix_set_client(struct svc_rqst *rqstp); extern int svcauth_unix_set_client(struct svc_rqst *rqstp);

View file

@ -969,16 +969,17 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
} }
static inline int static inline int
gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi *rsip) gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp,
struct xdr_netobj *out_handle, int *major_status)
{ {
struct rsc *rsci; struct rsc *rsci;
int rc; int rc;
if (rsip->major_status != GSS_S_COMPLETE) if (*major_status != GSS_S_COMPLETE)
return gss_write_null_verf(rqstp); return gss_write_null_verf(rqstp);
rsci = gss_svc_searchbyctx(cd, &rsip->out_handle); rsci = gss_svc_searchbyctx(cd, out_handle);
if (rsci == NULL) { if (rsci == NULL) {
rsip->major_status = GSS_S_NO_CONTEXT; *major_status = GSS_S_NO_CONTEXT;
return gss_write_null_verf(rqstp); return gss_write_null_verf(rqstp);
} }
rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN); rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
@ -986,6 +987,61 @@ gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi
return rc; return rc;
} }
static inline int
gss_read_verf(struct rpc_gss_wire_cred *gc,
struct kvec *argv, __be32 *authp,
struct xdr_netobj *in_handle,
struct xdr_netobj *in_token)
{
struct xdr_netobj tmpobj;
/* Read the verifier; should be NULL: */
*authp = rpc_autherr_badverf;
if (argv->iov_len < 2 * 4)
return SVC_DENIED;
if (svc_getnl(argv) != RPC_AUTH_NULL)
return SVC_DENIED;
if (svc_getnl(argv) != 0)
return SVC_DENIED;
/* Martial context handle and token for upcall: */
*authp = rpc_autherr_badcred;
if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
return SVC_DENIED;
if (dup_netobj(in_handle, &gc->gc_ctx))
return SVC_CLOSE;
*authp = rpc_autherr_badverf;
if (svc_safe_getnetobj(argv, &tmpobj)) {
kfree(in_handle->data);
return SVC_DENIED;
}
if (dup_netobj(in_token, &tmpobj)) {
kfree(in_handle->data);
return SVC_CLOSE;
}
return 0;
}
static inline int
gss_write_resv(struct kvec *resv, size_t size_limit,
struct xdr_netobj *out_handle, struct xdr_netobj *out_token,
int major_status, int minor_status)
{
if (resv->iov_len + 4 > size_limit)
return -1;
svc_putnl(resv, RPC_SUCCESS);
if (svc_safe_putnetobj(resv, out_handle))
return -1;
if (resv->iov_len + 3 * 4 > size_limit)
return -1;
svc_putnl(resv, major_status);
svc_putnl(resv, minor_status);
svc_putnl(resv, GSS_SEQ_WIN);
if (svc_safe_putnetobj(resv, out_token))
return -1;
return 0;
}
/* /*
* Having read the cred already and found we're in the context * Having read the cred already and found we're in the context
* initiation case, read the verifier and initiate (or check the results * initiation case, read the verifier and initiate (or check the results
@ -998,36 +1054,15 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
{ {
struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0]; struct kvec *resv = &rqstp->rq_res.head[0];
struct xdr_netobj tmpobj;
struct rsi *rsip, rsikey; struct rsi *rsip, rsikey;
int ret; int ret;
struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id); struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
/* Read the verifier; should be NULL: */
*authp = rpc_autherr_badverf;
if (argv->iov_len < 2 * 4)
return SVC_DENIED;
if (svc_getnl(argv) != RPC_AUTH_NULL)
return SVC_DENIED;
if (svc_getnl(argv) != 0)
return SVC_DENIED;
/* Martial context handle and token for upcall: */
*authp = rpc_autherr_badcred;
if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
return SVC_DENIED;
memset(&rsikey, 0, sizeof(rsikey)); memset(&rsikey, 0, sizeof(rsikey));
if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx)) ret = gss_read_verf(gc, argv, authp,
return SVC_CLOSE; &rsikey.in_handle, &rsikey.in_token);
*authp = rpc_autherr_badverf; if (ret)
if (svc_safe_getnetobj(argv, &tmpobj)) { return ret;
kfree(rsikey.in_handle.data);
return SVC_DENIED;
}
if (dup_netobj(&rsikey.in_token, &tmpobj)) {
kfree(rsikey.in_handle.data);
return SVC_CLOSE;
}
/* Perform upcall, or find upcall result: */ /* Perform upcall, or find upcall result: */
rsip = rsi_lookup(sn->rsi_cache, &rsikey); rsip = rsi_lookup(sn->rsi_cache, &rsikey);
@ -1040,19 +1075,12 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
ret = SVC_CLOSE; ret = SVC_CLOSE;
/* Got an answer to the upcall; use it: */ /* Got an answer to the upcall; use it: */
if (gss_write_init_verf(sn->rsc_cache, rqstp, rsip)) if (gss_write_init_verf(sn->rsc_cache, rqstp,
&rsip->out_handle, &rsip->major_status))
goto out; goto out;
if (resv->iov_len + 4 > PAGE_SIZE) if (gss_write_resv(resv, PAGE_SIZE,
goto out; &rsip->out_handle, &rsip->out_token,
svc_putnl(resv, RPC_SUCCESS); rsip->major_status, rsip->minor_status))
if (svc_safe_putnetobj(resv, &rsip->out_handle))
goto out;
if (resv->iov_len + 3 * 4 > PAGE_SIZE)
goto out;
svc_putnl(resv, rsip->major_status);
svc_putnl(resv, rsip->minor_status);
svc_putnl(resv, GSS_SEQ_WIN);
if (svc_safe_putnetobj(resv, &rsip->out_token))
goto out; goto out;
ret = SVC_COMPLETE; ret = SVC_COMPLETE;

View file

@ -347,17 +347,12 @@ static inline int ip_map_update(struct net *net, struct ip_map *ipm,
return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry); return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry);
} }
void svcauth_unix_purge(struct net *net)
void svcauth_unix_purge(void)
{ {
struct net *net; struct sunrpc_net *sn;
for_each_net(net) { sn = net_generic(net, sunrpc_net_id);
struct sunrpc_net *sn; cache_purge(sn->ip_map_cache);
sn = net_generic(net, sunrpc_net_id);
cache_purge(sn->ip_map_cache);
}
} }
EXPORT_SYMBOL_GPL(svcauth_unix_purge); EXPORT_SYMBOL_GPL(svcauth_unix_purge);