diff options
| -rw-r--r-- | fs/lockd/clntlock.c | 13 | ||||
| -rw-r--r-- | fs/lockd/svc.c | 7 | ||||
| -rw-r--r-- | fs/nfsd/export.c | 175 | ||||
| -rw-r--r-- | fs/nfsd/idmap.h | 8 | ||||
| -rw-r--r-- | fs/nfsd/netns.h | 6 | ||||
| -rw-r--r-- | fs/nfsd/nfs4idmap.c | 109 | ||||
| -rw-r--r-- | fs/nfsd/nfs4state.c | 13 | ||||
| -rw-r--r-- | fs/nfsd/nfsctl.c | 55 | ||||
| -rw-r--r-- | fs/nfsd/nfsfh.c | 2 | ||||
| -rw-r--r-- | fs/nfsd/nfssvc.c | 8 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 2 | ||||
| -rw-r--r-- | include/linux/lockd/bind.h | 4 | ||||
| -rw-r--r-- | include/linux/nfsd/export.h | 13 | ||||
| -rw-r--r-- | include/linux/sunrpc/svcauth.h | 3 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 100 | ||||
| -rw-r--r-- | net/sunrpc/svcauth_unix.c | 13 |
16 files changed, 322 insertions, 209 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index ba1dc2eebd1e..ca0a08001449 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
| @@ -56,7 +56,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) | |||
| 56 | u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4; | 56 | u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4; |
| 57 | int status; | 57 | int status; |
| 58 | 58 | ||
| 59 | status = lockd_up(); | 59 | status = lockd_up(nlm_init->net); |
| 60 | if (status < 0) | 60 | if (status < 0) |
| 61 | return ERR_PTR(status); | 61 | return ERR_PTR(status); |
| 62 | 62 | ||
| @@ -65,7 +65,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) | |||
| 65 | nlm_init->hostname, nlm_init->noresvport, | 65 | nlm_init->hostname, nlm_init->noresvport, |
| 66 | nlm_init->net); | 66 | nlm_init->net); |
| 67 | if (host == NULL) { | 67 | if (host == NULL) { |
| 68 | lockd_down(); | 68 | lockd_down(nlm_init->net); |
| 69 | return ERR_PTR(-ENOLCK); | 69 | return ERR_PTR(-ENOLCK); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| @@ -80,8 +80,10 @@ EXPORT_SYMBOL_GPL(nlmclnt_init); | |||
| 80 | */ | 80 | */ |
| 81 | void nlmclnt_done(struct nlm_host *host) | 81 | void nlmclnt_done(struct nlm_host *host) |
| 82 | { | 82 | { |
| 83 | struct net *net = host->net; | ||
| 84 | |||
| 83 | nlmclnt_release_host(host); | 85 | nlmclnt_release_host(host); |
| 84 | lockd_down(); | 86 | lockd_down(net); |
| 85 | } | 87 | } |
| 86 | EXPORT_SYMBOL_GPL(nlmclnt_done); | 88 | EXPORT_SYMBOL_GPL(nlmclnt_done); |
| 87 | 89 | ||
| @@ -220,11 +222,12 @@ reclaimer(void *ptr) | |||
| 220 | struct nlm_wait *block; | 222 | struct nlm_wait *block; |
| 221 | struct file_lock *fl, *next; | 223 | struct file_lock *fl, *next; |
| 222 | u32 nsmstate; | 224 | u32 nsmstate; |
| 225 | struct net *net = host->net; | ||
| 223 | 226 | ||
| 224 | allow_signal(SIGKILL); | 227 | allow_signal(SIGKILL); |
| 225 | 228 | ||
| 226 | down_write(&host->h_rwsem); | 229 | down_write(&host->h_rwsem); |
| 227 | lockd_up(); /* note: this cannot fail as lockd is already running */ | 230 | lockd_up(net); /* note: this cannot fail as lockd is already running */ |
| 228 | 231 | ||
| 229 | dprintk("lockd: reclaiming locks for host %s\n", host->h_name); | 232 | dprintk("lockd: reclaiming locks for host %s\n", host->h_name); |
| 230 | 233 | ||
| @@ -275,6 +278,6 @@ restart: | |||
| 275 | 278 | ||
| 276 | /* Release host handle after use */ | 279 | /* Release host handle after use */ |
| 277 | nlmclnt_release_host(host); | 280 | nlmclnt_release_host(host); |
| 278 | lockd_down(); | 281 | lockd_down(net); |
| 279 | return 0; | 282 | return 0; |
| 280 | } | 283 | } |
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index f49b9afc4436..1ead0750cdbb 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
| @@ -295,11 +295,10 @@ static void lockd_down_net(struct net *net) | |||
| 295 | /* | 295 | /* |
| 296 | * Bring up the lockd process if it's not already up. | 296 | * Bring up the lockd process if it's not already up. |
| 297 | */ | 297 | */ |
| 298 | int lockd_up(void) | 298 | int lockd_up(struct net *net) |
| 299 | { | 299 | { |
| 300 | struct svc_serv *serv; | 300 | struct svc_serv *serv; |
| 301 | int error = 0; | 301 | int error = 0; |
| 302 | struct net *net = current->nsproxy->net_ns; | ||
| 303 | 302 | ||
| 304 | mutex_lock(&nlmsvc_mutex); | 303 | mutex_lock(&nlmsvc_mutex); |
| 305 | /* | 304 | /* |
| @@ -378,12 +377,12 @@ EXPORT_SYMBOL_GPL(lockd_up); | |||
| 378 | * Decrement the user count and bring down lockd if we're the last. | 377 | * Decrement the user count and bring down lockd if we're the last. |
| 379 | */ | 378 | */ |
| 380 | void | 379 | void |
| 381 | lockd_down(void) | 380 | lockd_down(struct net *net) |
| 382 | { | 381 | { |
| 383 | mutex_lock(&nlmsvc_mutex); | 382 | mutex_lock(&nlmsvc_mutex); |
| 384 | if (nlmsvc_users) { | 383 | if (nlmsvc_users) { |
| 385 | if (--nlmsvc_users) { | 384 | if (--nlmsvc_users) { |
| 386 | lockd_down_net(current->nsproxy->net_ns); | 385 | lockd_down_net(net); |
| 387 | goto out; | 386 | goto out; |
| 388 | } | 387 | } |
| 389 | } else { | 388 | } else { |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 8e9689abbc0c..dcb52b884519 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
| @@ -15,11 +15,13 @@ | |||
| 15 | #include <linux/namei.h> | 15 | #include <linux/namei.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/exportfs.h> | 17 | #include <linux/exportfs.h> |
| 18 | #include <linux/sunrpc/svc_xprt.h> | ||
| 18 | 19 | ||
| 19 | #include <net/ipv6.h> | 20 | #include <net/ipv6.h> |
| 20 | 21 | ||
| 21 | #include "nfsd.h" | 22 | #include "nfsd.h" |
| 22 | #include "nfsfh.h" | 23 | #include "nfsfh.h" |
| 24 | #include "netns.h" | ||
| 23 | 25 | ||
| 24 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT | 26 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT |
| 25 | 27 | ||
| @@ -38,7 +40,6 @@ typedef struct svc_export svc_export; | |||
| 38 | #define EXPKEY_HASHBITS 8 | 40 | #define EXPKEY_HASHBITS 8 |
| 39 | #define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS) | 41 | #define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS) |
| 40 | #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) | 42 | #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) |
| 41 | static struct cache_head *expkey_table[EXPKEY_HASHMAX]; | ||
| 42 | 43 | ||
| 43 | static void expkey_put(struct kref *ref) | 44 | static void expkey_put(struct kref *ref) |
| 44 | { | 45 | { |
| @@ -71,9 +72,9 @@ static int expkey_upcall(struct cache_detail *cd, struct cache_head *h) | |||
| 71 | return sunrpc_cache_pipe_upcall(cd, h, expkey_request); | 72 | return sunrpc_cache_pipe_upcall(cd, h, expkey_request); |
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); | 75 | static struct svc_expkey *svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new, |
| 75 | static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); | 76 | struct svc_expkey *old); |
| 76 | static struct cache_detail svc_expkey_cache; | 77 | static struct svc_expkey *svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *); |
| 77 | 78 | ||
| 78 | static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | 79 | static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) |
| 79 | { | 80 | { |
| @@ -131,7 +132,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
| 131 | key.ek_fsidtype = fsidtype; | 132 | key.ek_fsidtype = fsidtype; |
| 132 | memcpy(key.ek_fsid, buf, len); | 133 | memcpy(key.ek_fsid, buf, len); |
| 133 | 134 | ||
| 134 | ek = svc_expkey_lookup(&key); | 135 | ek = svc_expkey_lookup(cd, &key); |
| 135 | err = -ENOMEM; | 136 | err = -ENOMEM; |
| 136 | if (!ek) | 137 | if (!ek) |
| 137 | goto out; | 138 | goto out; |
| @@ -145,7 +146,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
| 145 | err = 0; | 146 | err = 0; |
| 146 | if (len == 0) { | 147 | if (len == 0) { |
| 147 | set_bit(CACHE_NEGATIVE, &key.h.flags); | 148 | set_bit(CACHE_NEGATIVE, &key.h.flags); |
| 148 | ek = svc_expkey_update(&key, ek); | 149 | ek = svc_expkey_update(cd, &key, ek); |
| 149 | if (!ek) | 150 | if (!ek) |
| 150 | err = -ENOMEM; | 151 | err = -ENOMEM; |
| 151 | } else { | 152 | } else { |
| @@ -155,7 +156,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
| 155 | 156 | ||
| 156 | dprintk("Found the path %s\n", buf); | 157 | dprintk("Found the path %s\n", buf); |
| 157 | 158 | ||
| 158 | ek = svc_expkey_update(&key, ek); | 159 | ek = svc_expkey_update(cd, &key, ek); |
| 159 | if (!ek) | 160 | if (!ek) |
| 160 | err = -ENOMEM; | 161 | err = -ENOMEM; |
| 161 | path_put(&key.ek_path); | 162 | path_put(&key.ek_path); |
| @@ -163,7 +164,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
| 163 | cache_flush(); | 164 | cache_flush(); |
| 164 | out: | 165 | out: |
| 165 | if (ek) | 166 | if (ek) |
| 166 | cache_put(&ek->h, &svc_expkey_cache); | 167 | cache_put(&ek->h, cd); |
| 167 | if (dom) | 168 | if (dom) |
| 168 | auth_domain_put(dom); | 169 | auth_domain_put(dom); |
| 169 | kfree(buf); | 170 | kfree(buf); |
| @@ -239,10 +240,9 @@ static struct cache_head *expkey_alloc(void) | |||
| 239 | return NULL; | 240 | return NULL; |
| 240 | } | 241 | } |
| 241 | 242 | ||
| 242 | static struct cache_detail svc_expkey_cache = { | 243 | static struct cache_detail svc_expkey_cache_template = { |
| 243 | .owner = THIS_MODULE, | 244 | .owner = THIS_MODULE, |
| 244 | .hash_size = EXPKEY_HASHMAX, | 245 | .hash_size = EXPKEY_HASHMAX, |
| 245 | .hash_table = expkey_table, | ||
| 246 | .name = "nfsd.fh", | 246 | .name = "nfsd.fh", |
| 247 | .cache_put = expkey_put, | 247 | .cache_put = expkey_put, |
| 248 | .cache_upcall = expkey_upcall, | 248 | .cache_upcall = expkey_upcall, |
| @@ -268,13 +268,12 @@ svc_expkey_hash(struct svc_expkey *item) | |||
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | static struct svc_expkey * | 270 | static struct svc_expkey * |
| 271 | svc_expkey_lookup(struct svc_expkey *item) | 271 | svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *item) |
| 272 | { | 272 | { |
| 273 | struct cache_head *ch; | 273 | struct cache_head *ch; |
| 274 | int hash = svc_expkey_hash(item); | 274 | int hash = svc_expkey_hash(item); |
| 275 | 275 | ||
| 276 | ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h, | 276 | ch = sunrpc_cache_lookup(cd, &item->h, hash); |
| 277 | hash); | ||
| 278 | if (ch) | 277 | if (ch) |
| 279 | return container_of(ch, struct svc_expkey, h); | 278 | return container_of(ch, struct svc_expkey, h); |
| 280 | else | 279 | else |
| @@ -282,13 +281,13 @@ svc_expkey_lookup(struct svc_expkey *item) | |||
| 282 | } | 281 | } |
| 283 | 282 | ||
| 284 | static struct svc_expkey * | 283 | static struct svc_expkey * |
| 285 | svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) | 284 | svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new, |
| 285 | struct svc_expkey *old) | ||
| 286 | { | 286 | { |
| 287 | struct cache_head *ch; | 287 | struct cache_head *ch; |
| 288 | int hash = svc_expkey_hash(new); | 288 | int hash = svc_expkey_hash(new); |
| 289 | 289 | ||
| 290 | ch = sunrpc_cache_update(&svc_expkey_cache, &new->h, | 290 | ch = sunrpc_cache_update(cd, &new->h, &old->h, hash); |
| 291 | &old->h, hash); | ||
| 292 | if (ch) | 291 | if (ch) |
| 293 | return container_of(ch, struct svc_expkey, h); | 292 | return container_of(ch, struct svc_expkey, h); |
| 294 | else | 293 | else |
| @@ -299,8 +298,6 @@ svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) | |||
| 299 | #define EXPORT_HASHBITS 8 | 298 | #define EXPORT_HASHBITS 8 |
| 300 | #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) | 299 | #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) |
| 301 | 300 | ||
| 302 | static struct cache_head *export_table[EXPORT_HASHMAX]; | ||
| 303 | |||
| 304 | static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc) | 301 | static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc) |
| 305 | { | 302 | { |
| 306 | int i; | 303 | int i; |
| @@ -525,6 +522,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
| 525 | goto out1; | 522 | goto out1; |
| 526 | 523 | ||
| 527 | exp.ex_client = dom; | 524 | exp.ex_client = dom; |
| 525 | exp.cd = cd; | ||
| 528 | 526 | ||
| 529 | /* expiry */ | 527 | /* expiry */ |
| 530 | err = -EINVAL; | 528 | err = -EINVAL; |
| @@ -672,6 +670,7 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) | |||
| 672 | new->ex_fslocs.locations = NULL; | 670 | new->ex_fslocs.locations = NULL; |
| 673 | new->ex_fslocs.locations_count = 0; | 671 | new->ex_fslocs.locations_count = 0; |
| 674 | new->ex_fslocs.migrated = 0; | 672 | new->ex_fslocs.migrated = 0; |
| 673 | new->cd = item->cd; | ||
| 675 | } | 674 | } |
| 676 | 675 | ||
| 677 | static void export_update(struct cache_head *cnew, struct cache_head *citem) | 676 | static void export_update(struct cache_head *cnew, struct cache_head *citem) |
| @@ -707,10 +706,9 @@ static struct cache_head *svc_export_alloc(void) | |||
| 707 | return NULL; | 706 | return NULL; |
| 708 | } | 707 | } |
| 709 | 708 | ||
| 710 | struct cache_detail svc_export_cache = { | 709 | struct cache_detail svc_export_cache_template = { |
| 711 | .owner = THIS_MODULE, | 710 | .owner = THIS_MODULE, |
| 712 | .hash_size = EXPORT_HASHMAX, | 711 | .hash_size = EXPORT_HASHMAX, |
| 713 | .hash_table = export_table, | ||
| 714 | .name = "nfsd.export", | 712 | .name = "nfsd.export", |
| 715 | .cache_put = svc_export_put, | 713 | .cache_put = svc_export_put, |
| 716 | .cache_upcall = svc_export_upcall, | 714 | .cache_upcall = svc_export_upcall, |
| @@ -739,8 +737,7 @@ svc_export_lookup(struct svc_export *exp) | |||
| 739 | struct cache_head *ch; | 737 | struct cache_head *ch; |
| 740 | int hash = svc_export_hash(exp); | 738 | int hash = svc_export_hash(exp); |
| 741 | 739 | ||
| 742 | ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h, | 740 | ch = sunrpc_cache_lookup(exp->cd, &exp->h, hash); |
| 743 | hash); | ||
| 744 | if (ch) | 741 | if (ch) |
| 745 | return container_of(ch, struct svc_export, h); | 742 | return container_of(ch, struct svc_export, h); |
| 746 | else | 743 | else |
| @@ -753,9 +750,7 @@ svc_export_update(struct svc_export *new, struct svc_export *old) | |||
| 753 | struct cache_head *ch; | 750 | struct cache_head *ch; |
| 754 | int hash = svc_export_hash(old); | 751 | int hash = svc_export_hash(old); |
| 755 | 752 | ||
| 756 | ch = sunrpc_cache_update(&svc_export_cache, &new->h, | 753 | ch = sunrpc_cache_update(old->cd, &new->h, &old->h, hash); |
| 757 | &old->h, | ||
| 758 | hash); | ||
| 759 | if (ch) | 754 | if (ch) |
| 760 | return container_of(ch, struct svc_export, h); | 755 | return container_of(ch, struct svc_export, h); |
| 761 | else | 756 | else |
| @@ -764,7 +759,8 @@ svc_export_update(struct svc_export *new, struct svc_export *old) | |||
| 764 | 759 | ||
| 765 | 760 | ||
| 766 | static struct svc_expkey * | 761 | static struct svc_expkey * |
| 767 | exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) | 762 | exp_find_key(struct cache_detail *cd, svc_client *clp, int fsid_type, |
| 763 | u32 *fsidv, struct cache_req *reqp) | ||
| 768 | { | 764 | { |
| 769 | struct svc_expkey key, *ek; | 765 | struct svc_expkey key, *ek; |
| 770 | int err; | 766 | int err; |
| @@ -776,18 +772,18 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) | |||
| 776 | key.ek_fsidtype = fsid_type; | 772 | key.ek_fsidtype = fsid_type; |
| 777 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); | 773 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); |
| 778 | 774 | ||
| 779 | ek = svc_expkey_lookup(&key); | 775 | ek = svc_expkey_lookup(cd, &key); |
| 780 | if (ek == NULL) | 776 | if (ek == NULL) |
| 781 | return ERR_PTR(-ENOMEM); | 777 | return ERR_PTR(-ENOMEM); |
| 782 | err = cache_check(&svc_expkey_cache, &ek->h, reqp); | 778 | err = cache_check(cd, &ek->h, reqp); |
| 783 | if (err) | 779 | if (err) |
| 784 | return ERR_PTR(err); | 780 | return ERR_PTR(err); |
| 785 | return ek; | 781 | return ek; |
| 786 | } | 782 | } |
| 787 | 783 | ||
| 788 | 784 | ||
| 789 | static svc_export *exp_get_by_name(svc_client *clp, const struct path *path, | 785 | static svc_export *exp_get_by_name(struct cache_detail *cd, svc_client *clp, |
| 790 | struct cache_req *reqp) | 786 | const struct path *path, struct cache_req *reqp) |
| 791 | { | 787 | { |
| 792 | struct svc_export *exp, key; | 788 | struct svc_export *exp, key; |
| 793 | int err; | 789 | int err; |
| @@ -797,11 +793,12 @@ static svc_export *exp_get_by_name(svc_client *clp, const struct path *path, | |||
| 797 | 793 | ||
| 798 | key.ex_client = clp; | 794 | key.ex_client = clp; |
| 799 | key.ex_path = *path; | 795 | key.ex_path = *path; |
| 796 | key.cd = cd; | ||
| 800 | 797 | ||
| 801 | exp = svc_export_lookup(&key); | 798 | exp = svc_export_lookup(&key); |
| 802 | if (exp == NULL) | 799 | if (exp == NULL) |
| 803 | return ERR_PTR(-ENOMEM); | 800 | return ERR_PTR(-ENOMEM); |
| 804 | err = cache_check(&svc_export_cache, &exp->h, reqp); | 801 | err = cache_check(cd, &exp->h, reqp); |
| 805 | if (err) | 802 | if (err) |
| 806 | return ERR_PTR(err); | 803 | return ERR_PTR(err); |
| 807 | return exp; | 804 | return exp; |
| @@ -810,16 +807,17 @@ static svc_export *exp_get_by_name(svc_client *clp, const struct path *path, | |||
| 810 | /* | 807 | /* |
| 811 | * Find the export entry for a given dentry. | 808 | * Find the export entry for a given dentry. |
| 812 | */ | 809 | */ |
| 813 | static struct svc_export *exp_parent(svc_client *clp, struct path *path) | 810 | static struct svc_export *exp_parent(struct cache_detail *cd, svc_client *clp, |
| 811 | struct path *path) | ||
| 814 | { | 812 | { |
| 815 | struct dentry *saved = dget(path->dentry); | 813 | struct dentry *saved = dget(path->dentry); |
| 816 | svc_export *exp = exp_get_by_name(clp, path, NULL); | 814 | svc_export *exp = exp_get_by_name(cd, clp, path, NULL); |
| 817 | 815 | ||
| 818 | while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) { | 816 | while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) { |
| 819 | struct dentry *parent = dget_parent(path->dentry); | 817 | struct dentry *parent = dget_parent(path->dentry); |
| 820 | dput(path->dentry); | 818 | dput(path->dentry); |
| 821 | path->dentry = parent; | 819 | path->dentry = parent; |
| 822 | exp = exp_get_by_name(clp, path, NULL); | 820 | exp = exp_get_by_name(cd, clp, path, NULL); |
| 823 | } | 821 | } |
| 824 | dput(path->dentry); | 822 | dput(path->dentry); |
| 825 | path->dentry = saved; | 823 | path->dentry = saved; |
| @@ -834,13 +832,16 @@ static struct svc_export *exp_parent(svc_client *clp, struct path *path) | |||
| 834 | * since its harder to fool a kernel module than a user space program. | 832 | * since its harder to fool a kernel module than a user space program. |
| 835 | */ | 833 | */ |
| 836 | int | 834 | int |
| 837 | exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize) | 835 | exp_rootfh(struct net *net, svc_client *clp, char *name, |
| 836 | struct knfsd_fh *f, int maxsize) | ||
| 838 | { | 837 | { |
| 839 | struct svc_export *exp; | 838 | struct svc_export *exp; |
| 840 | struct path path; | 839 | struct path path; |
| 841 | struct inode *inode; | 840 | struct inode *inode; |
| 842 | struct svc_fh fh; | 841 | struct svc_fh fh; |
| 843 | int err; | 842 | int err; |
| 843 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 844 | struct cache_detail *cd = nn->svc_export_cache; | ||
| 844 | 845 | ||
| 845 | err = -EPERM; | 846 | err = -EPERM; |
| 846 | /* NB: we probably ought to check that it's NUL-terminated */ | 847 | /* 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) | |||
| 853 | dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", | 854 | dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", |
| 854 | name, path.dentry, clp->name, | 855 | name, path.dentry, clp->name, |
| 855 | inode->i_sb->s_id, inode->i_ino); | 856 | inode->i_sb->s_id, inode->i_ino); |
| 856 | exp = exp_parent(clp, &path); | 857 | exp = exp_parent(cd, clp, &path); |
| 857 | if (IS_ERR(exp)) { | 858 | if (IS_ERR(exp)) { |
| 858 | err = PTR_ERR(exp); | 859 | err = PTR_ERR(exp); |
| 859 | goto out; | 860 | goto out; |
| @@ -875,16 +876,18 @@ out: | |||
| 875 | return err; | 876 | return err; |
| 876 | } | 877 | } |
| 877 | 878 | ||
| 878 | static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type, | 879 | static struct svc_export *exp_find(struct cache_detail *cd, |
| 880 | struct auth_domain *clp, int fsid_type, | ||
| 879 | u32 *fsidv, struct cache_req *reqp) | 881 | u32 *fsidv, struct cache_req *reqp) |
| 880 | { | 882 | { |
| 881 | struct svc_export *exp; | 883 | struct svc_export *exp; |
| 882 | struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); | 884 | struct nfsd_net *nn = net_generic(cd->net, nfsd_net_id); |
| 885 | struct svc_expkey *ek = exp_find_key(nn->svc_expkey_cache, clp, fsid_type, fsidv, reqp); | ||
| 883 | if (IS_ERR(ek)) | 886 | if (IS_ERR(ek)) |
| 884 | return ERR_CAST(ek); | 887 | return ERR_CAST(ek); |
| 885 | 888 | ||
| 886 | exp = exp_get_by_name(clp, &ek->ek_path, reqp); | 889 | exp = exp_get_by_name(cd, clp, &ek->ek_path, reqp); |
| 887 | cache_put(&ek->h, &svc_expkey_cache); | 890 | cache_put(&ek->h, nn->svc_expkey_cache); |
| 888 | 891 | ||
| 889 | if (IS_ERR(exp)) | 892 | if (IS_ERR(exp)) |
| 890 | return ERR_CAST(exp); | 893 | return ERR_CAST(exp); |
| @@ -926,12 +929,14 @@ struct svc_export * | |||
| 926 | rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path) | 929 | rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path) |
| 927 | { | 930 | { |
| 928 | struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); | 931 | struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); |
| 932 | struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); | ||
| 933 | struct cache_detail *cd = nn->svc_export_cache; | ||
| 929 | 934 | ||
| 930 | if (rqstp->rq_client == NULL) | 935 | if (rqstp->rq_client == NULL) |
| 931 | goto gss; | 936 | goto gss; |
| 932 | 937 | ||
| 933 | /* First try the auth_unix client: */ | 938 | /* First try the auth_unix client: */ |
| 934 | exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle); | 939 | exp = exp_get_by_name(cd, rqstp->rq_client, path, &rqstp->rq_chandle); |
| 935 | if (PTR_ERR(exp) == -ENOENT) | 940 | if (PTR_ERR(exp) == -ENOENT) |
| 936 | goto gss; | 941 | goto gss; |
| 937 | if (IS_ERR(exp)) | 942 | if (IS_ERR(exp)) |
| @@ -943,7 +948,7 @@ gss: | |||
| 943 | /* Otherwise, try falling back on gss client */ | 948 | /* Otherwise, try falling back on gss client */ |
| 944 | if (rqstp->rq_gssclient == NULL) | 949 | if (rqstp->rq_gssclient == NULL) |
| 945 | return exp; | 950 | return exp; |
| 946 | gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle); | 951 | gssexp = exp_get_by_name(cd, rqstp->rq_gssclient, path, &rqstp->rq_chandle); |
| 947 | if (PTR_ERR(gssexp) == -ENOENT) | 952 | if (PTR_ERR(gssexp) == -ENOENT) |
| 948 | return exp; | 953 | return exp; |
| 949 | if (!IS_ERR(exp)) | 954 | if (!IS_ERR(exp)) |
| @@ -955,12 +960,15 @@ struct svc_export * | |||
| 955 | rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv) | 960 | rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv) |
| 956 | { | 961 | { |
| 957 | struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); | 962 | struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); |
| 963 | struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); | ||
| 964 | struct cache_detail *cd = nn->svc_export_cache; | ||
| 958 | 965 | ||
| 959 | if (rqstp->rq_client == NULL) | 966 | if (rqstp->rq_client == NULL) |
| 960 | goto gss; | 967 | goto gss; |
| 961 | 968 | ||
| 962 | /* First try the auth_unix client: */ | 969 | /* First try the auth_unix client: */ |
| 963 | exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle); | 970 | exp = exp_find(cd, rqstp->rq_client, fsid_type, |
| 971 | fsidv, &rqstp->rq_chandle); | ||
| 964 | if (PTR_ERR(exp) == -ENOENT) | 972 | if (PTR_ERR(exp) == -ENOENT) |
| 965 | goto gss; | 973 | goto gss; |
| 966 | if (IS_ERR(exp)) | 974 | if (IS_ERR(exp)) |
| @@ -972,7 +980,7 @@ gss: | |||
| 972 | /* Otherwise, try falling back on gss client */ | 980 | /* Otherwise, try falling back on gss client */ |
| 973 | if (rqstp->rq_gssclient == NULL) | 981 | if (rqstp->rq_gssclient == NULL) |
| 974 | return exp; | 982 | return exp; |
| 975 | gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv, | 983 | gssexp = exp_find(cd, rqstp->rq_gssclient, fsid_type, fsidv, |
| 976 | &rqstp->rq_chandle); | 984 | &rqstp->rq_chandle); |
| 977 | if (PTR_ERR(gssexp) == -ENOENT) | 985 | if (PTR_ERR(gssexp) == -ENOENT) |
| 978 | return exp; | 986 | return exp; |
| @@ -1029,13 +1037,15 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
| 1029 | /* Iterator */ | 1037 | /* Iterator */ |
| 1030 | 1038 | ||
| 1031 | static void *e_start(struct seq_file *m, loff_t *pos) | 1039 | static void *e_start(struct seq_file *m, loff_t *pos) |
| 1032 | __acquires(svc_export_cache.hash_lock) | 1040 | __acquires(((struct cache_detail *)m->private)->hash_lock) |
| 1033 | { | 1041 | { |
| 1034 | loff_t n = *pos; | 1042 | loff_t n = *pos; |
| 1035 | unsigned hash, export; | 1043 | unsigned hash, export; |
| 1036 | struct cache_head *ch; | 1044 | struct cache_head *ch; |
| 1037 | 1045 | struct cache_detail *cd = m->private; | |
| 1038 | read_lock(&svc_export_cache.hash_lock); | 1046 | struct cache_head **export_table = cd->hash_table; |
| 1047 | |||
| 1048 | read_lock(&cd->hash_lock); | ||
| 1039 | if (!n--) | 1049 | if (!n--) |
| 1040 | return SEQ_START_TOKEN; | 1050 | return SEQ_START_TOKEN; |
| 1041 | hash = n >> 32; | 1051 | hash = n >> 32; |
| @@ -1060,6 +1070,8 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos) | |||
| 1060 | { | 1070 | { |
| 1061 | struct cache_head *ch = p; | 1071 | struct cache_head *ch = p; |
| 1062 | int hash = (*pos >> 32); | 1072 | int hash = (*pos >> 32); |
| 1073 | struct cache_detail *cd = m->private; | ||
| 1074 | struct cache_head **export_table = cd->hash_table; | ||
| 1063 | 1075 | ||
| 1064 | if (p == SEQ_START_TOKEN) | 1076 | if (p == SEQ_START_TOKEN) |
| 1065 | hash = 0; | 1077 | hash = 0; |
| @@ -1082,9 +1094,11 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos) | |||
| 1082 | } | 1094 | } |
| 1083 | 1095 | ||
| 1084 | static void e_stop(struct seq_file *m, void *p) | 1096 | static void e_stop(struct seq_file *m, void *p) |
| 1085 | __releases(svc_export_cache.hash_lock) | 1097 | __releases(((struct cache_detail *)m->private)->hash_lock) |
| 1086 | { | 1098 | { |
| 1087 | read_unlock(&svc_export_cache.hash_lock); | 1099 | struct cache_detail *cd = m->private; |
| 1100 | |||
| 1101 | read_unlock(&cd->hash_lock); | ||
| 1088 | } | 1102 | } |
| 1089 | 1103 | ||
| 1090 | static struct flags { | 1104 | static struct flags { |
| @@ -1195,6 +1209,7 @@ static int e_show(struct seq_file *m, void *p) | |||
| 1195 | { | 1209 | { |
| 1196 | struct cache_head *cp = p; | 1210 | struct cache_head *cp = p; |
| 1197 | struct svc_export *exp = container_of(cp, struct svc_export, h); | 1211 | struct svc_export *exp = container_of(cp, struct svc_export, h); |
| 1212 | struct cache_detail *cd = m->private; | ||
| 1198 | 1213 | ||
| 1199 | if (p == SEQ_START_TOKEN) { | 1214 | if (p == SEQ_START_TOKEN) { |
| 1200 | seq_puts(m, "# Version 1.1\n"); | 1215 | seq_puts(m, "# Version 1.1\n"); |
| @@ -1203,10 +1218,10 @@ static int e_show(struct seq_file *m, void *p) | |||
| 1203 | } | 1218 | } |
| 1204 | 1219 | ||
| 1205 | cache_get(&exp->h); | 1220 | cache_get(&exp->h); |
| 1206 | if (cache_check(&svc_export_cache, &exp->h, NULL)) | 1221 | if (cache_check(cd, &exp->h, NULL)) |
| 1207 | return 0; | 1222 | return 0; |
| 1208 | cache_put(&exp->h, &svc_export_cache); | 1223 | exp_put(exp); |
| 1209 | return svc_export_show(m, &svc_export_cache, cp); | 1224 | return svc_export_show(m, cd, cp); |
| 1210 | } | 1225 | } |
| 1211 | 1226 | ||
| 1212 | const struct seq_operations nfs_exports_op = { | 1227 | const struct seq_operations nfs_exports_op = { |
| @@ -1216,48 +1231,70 @@ const struct seq_operations nfs_exports_op = { | |||
| 1216 | .show = e_show, | 1231 | .show = e_show, |
| 1217 | }; | 1232 | }; |
| 1218 | 1233 | ||
| 1219 | |||
| 1220 | /* | 1234 | /* |
| 1221 | * Initialize the exports module. | 1235 | * Initialize the exports module. |
| 1222 | */ | 1236 | */ |
| 1223 | int | 1237 | int |
| 1224 | nfsd_export_init(void) | 1238 | nfsd_export_init(struct net *net) |
| 1225 | { | 1239 | { |
| 1226 | int rv; | 1240 | int rv; |
| 1227 | dprintk("nfsd: initializing export module.\n"); | 1241 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 1242 | |||
| 1243 | dprintk("nfsd: initializing export module (net: %p).\n", net); | ||
| 1228 | 1244 | ||
| 1229 | rv = cache_register_net(&svc_export_cache, &init_net); | 1245 | nn->svc_export_cache = cache_create_net(&svc_export_cache_template, net); |
| 1246 | if (IS_ERR(nn->svc_export_cache)) | ||
| 1247 | return PTR_ERR(nn->svc_export_cache); | ||
| 1248 | rv = cache_register_net(nn->svc_export_cache, net); | ||
| 1230 | if (rv) | 1249 | if (rv) |
| 1231 | return rv; | 1250 | goto destroy_export_cache; |
| 1232 | rv = cache_register_net(&svc_expkey_cache, &init_net); | 1251 | |
| 1252 | nn->svc_expkey_cache = cache_create_net(&svc_expkey_cache_template, net); | ||
| 1253 | if (IS_ERR(nn->svc_expkey_cache)) { | ||
| 1254 | rv = PTR_ERR(nn->svc_expkey_cache); | ||
| 1255 | goto unregister_export_cache; | ||
| 1256 | } | ||
| 1257 | rv = cache_register_net(nn->svc_expkey_cache, net); | ||
| 1233 | if (rv) | 1258 | if (rv) |
| 1234 | cache_unregister_net(&svc_export_cache, &init_net); | 1259 | goto destroy_expkey_cache; |
| 1235 | return rv; | 1260 | return 0; |
| 1236 | 1261 | ||
| 1262 | destroy_expkey_cache: | ||
| 1263 | cache_destroy_net(nn->svc_expkey_cache, net); | ||
| 1264 | unregister_export_cache: | ||
| 1265 | cache_unregister_net(nn->svc_export_cache, net); | ||
| 1266 | destroy_export_cache: | ||
| 1267 | cache_destroy_net(nn->svc_export_cache, net); | ||
| 1268 | return rv; | ||
| 1237 | } | 1269 | } |
| 1238 | 1270 | ||
| 1239 | /* | 1271 | /* |
| 1240 | * Flush exports table - called when last nfsd thread is killed | 1272 | * Flush exports table - called when last nfsd thread is killed |
| 1241 | */ | 1273 | */ |
| 1242 | void | 1274 | void |
| 1243 | nfsd_export_flush(void) | 1275 | nfsd_export_flush(struct net *net) |
| 1244 | { | 1276 | { |
| 1245 | cache_purge(&svc_expkey_cache); | 1277 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 1246 | cache_purge(&svc_export_cache); | 1278 | |
| 1279 | cache_purge(nn->svc_expkey_cache); | ||
| 1280 | cache_purge(nn->svc_export_cache); | ||
| 1247 | } | 1281 | } |
| 1248 | 1282 | ||
| 1249 | /* | 1283 | /* |
| 1250 | * Shutdown the exports module. | 1284 | * Shutdown the exports module. |
| 1251 | */ | 1285 | */ |
| 1252 | void | 1286 | void |
| 1253 | nfsd_export_shutdown(void) | 1287 | nfsd_export_shutdown(struct net *net) |
| 1254 | { | 1288 | { |
| 1289 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 1255 | 1290 | ||
| 1256 | dprintk("nfsd: shutting down export module.\n"); | 1291 | dprintk("nfsd: shutting down export module (net: %p).\n", net); |
| 1257 | 1292 | ||
| 1258 | cache_unregister_net(&svc_expkey_cache, &init_net); | 1293 | cache_unregister_net(nn->svc_expkey_cache, net); |
| 1259 | cache_unregister_net(&svc_export_cache, &init_net); | 1294 | cache_unregister_net(nn->svc_export_cache, net); |
| 1260 | svcauth_unix_purge(); | 1295 | cache_destroy_net(nn->svc_expkey_cache, net); |
| 1296 | cache_destroy_net(nn->svc_export_cache, net); | ||
| 1297 | svcauth_unix_purge(net); | ||
| 1261 | 1298 | ||
| 1262 | dprintk("nfsd: export shutdown complete.\n"); | 1299 | dprintk("nfsd: export shutdown complete (net: %p).\n", net); |
| 1263 | } | 1300 | } |
diff --git a/fs/nfsd/idmap.h b/fs/nfsd/idmap.h index 2f3be1321534..9d513efc01ba 100644 --- a/fs/nfsd/idmap.h +++ b/fs/nfsd/idmap.h | |||
| @@ -42,14 +42,14 @@ | |||
| 42 | #define IDMAP_NAMESZ 128 | 42 | #define IDMAP_NAMESZ 128 |
| 43 | 43 | ||
| 44 | #ifdef CONFIG_NFSD_V4 | 44 | #ifdef CONFIG_NFSD_V4 |
| 45 | int nfsd_idmap_init(void); | 45 | int nfsd_idmap_init(struct net *); |
| 46 | void nfsd_idmap_shutdown(void); | 46 | void nfsd_idmap_shutdown(struct net *); |
| 47 | #else | 47 | #else |
| 48 | static inline int nfsd_idmap_init(void) | 48 | static inline int nfsd_idmap_init(struct net *net) |
| 49 | { | 49 | { |
| 50 | return 0; | 50 | return 0; |
| 51 | } | 51 | } |
| 52 | static inline void nfsd_idmap_shutdown(void) | 52 | static inline void nfsd_idmap_shutdown(struct net *net) |
| 53 | { | 53 | { |
| 54 | } | 54 | } |
| 55 | #endif | 55 | #endif |
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 12e0cff435b4..39365636b244 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h | |||
| @@ -28,6 +28,12 @@ struct cld_net; | |||
| 28 | 28 | ||
| 29 | struct nfsd_net { | 29 | struct nfsd_net { |
| 30 | struct cld_net *cld_net; | 30 | struct cld_net *cld_net; |
| 31 | |||
| 32 | struct cache_detail *svc_expkey_cache; | ||
| 33 | struct cache_detail *svc_export_cache; | ||
| 34 | |||
| 35 | struct cache_detail *idtoname_cache; | ||
| 36 | struct cache_detail *nametoid_cache; | ||
| 31 | }; | 37 | }; |
| 32 | 38 | ||
| 33 | extern int nfsd_net_id; | 39 | extern int nfsd_net_id; |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 322d11ce06a4..286a7f8f2024 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
| @@ -36,9 +36,11 @@ | |||
| 36 | #include <linux/seq_file.h> | 36 | #include <linux/seq_file.h> |
| 37 | #include <linux/sched.h> | 37 | #include <linux/sched.h> |
| 38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
| 39 | #include <linux/sunrpc/svc_xprt.h> | ||
| 39 | #include <net/net_namespace.h> | 40 | #include <net/net_namespace.h> |
| 40 | #include "idmap.h" | 41 | #include "idmap.h" |
| 41 | #include "nfsd.h" | 42 | #include "nfsd.h" |
| 43 | #include "netns.h" | ||
| 42 | 44 | ||
| 43 | /* | 45 | /* |
| 44 | * Turn off idmapping when using AUTH_SYS. | 46 | * Turn off idmapping when using AUTH_SYS. |
| @@ -107,8 +109,6 @@ ent_alloc(void) | |||
| 107 | * ID -> Name cache | 109 | * ID -> Name cache |
| 108 | */ | 110 | */ |
| 109 | 111 | ||
| 110 | static struct cache_head *idtoname_table[ENT_HASHMAX]; | ||
| 111 | |||
| 112 | static uint32_t | 112 | static uint32_t |
| 113 | idtoname_hash(struct ent *ent) | 113 | idtoname_hash(struct ent *ent) |
| 114 | { | 114 | { |
| @@ -183,13 +183,13 @@ warn_no_idmapd(struct cache_detail *detail, int has_died) | |||
| 183 | 183 | ||
| 184 | 184 | ||
| 185 | static int idtoname_parse(struct cache_detail *, char *, int); | 185 | static int idtoname_parse(struct cache_detail *, char *, int); |
| 186 | static struct ent *idtoname_lookup(struct ent *); | 186 | static struct ent *idtoname_lookup(struct cache_detail *, struct ent *); |
| 187 | static struct ent *idtoname_update(struct ent *, struct ent *); | 187 | static struct ent *idtoname_update(struct cache_detail *, struct ent *, |
| 188 | struct ent *); | ||
| 188 | 189 | ||
| 189 | static struct cache_detail idtoname_cache = { | 190 | static struct cache_detail idtoname_cache_template = { |
| 190 | .owner = THIS_MODULE, | 191 | .owner = THIS_MODULE, |
| 191 | .hash_size = ENT_HASHMAX, | 192 | .hash_size = ENT_HASHMAX, |
| 192 | .hash_table = idtoname_table, | ||
| 193 | .name = "nfs4.idtoname", | 193 | .name = "nfs4.idtoname", |
| 194 | .cache_put = ent_put, | 194 | .cache_put = ent_put, |
| 195 | .cache_upcall = idtoname_upcall, | 195 | .cache_upcall = idtoname_upcall, |
| @@ -244,7 +244,7 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen) | |||
| 244 | goto out; | 244 | goto out; |
| 245 | 245 | ||
| 246 | error = -ENOMEM; | 246 | error = -ENOMEM; |
| 247 | res = idtoname_lookup(&ent); | 247 | res = idtoname_lookup(cd, &ent); |
| 248 | if (!res) | 248 | if (!res) |
| 249 | goto out; | 249 | goto out; |
| 250 | 250 | ||
| @@ -260,11 +260,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen) | |||
| 260 | else | 260 | else |
| 261 | memcpy(ent.name, buf1, sizeof(ent.name)); | 261 | memcpy(ent.name, buf1, sizeof(ent.name)); |
| 262 | error = -ENOMEM; | 262 | error = -ENOMEM; |
| 263 | res = idtoname_update(&ent, res); | 263 | res = idtoname_update(cd, &ent, res); |
| 264 | if (res == NULL) | 264 | if (res == NULL) |
| 265 | goto out; | 265 | goto out; |
| 266 | 266 | ||
| 267 | cache_put(&res->h, &idtoname_cache); | 267 | cache_put(&res->h, cd); |
| 268 | 268 | ||
| 269 | error = 0; | 269 | error = 0; |
| 270 | out: | 270 | out: |
| @@ -275,10 +275,9 @@ out: | |||
| 275 | 275 | ||
| 276 | 276 | ||
| 277 | static struct ent * | 277 | static struct ent * |
| 278 | idtoname_lookup(struct ent *item) | 278 | idtoname_lookup(struct cache_detail *cd, struct ent *item) |
| 279 | { | 279 | { |
| 280 | struct cache_head *ch = sunrpc_cache_lookup(&idtoname_cache, | 280 | struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h, |
| 281 | &item->h, | ||
| 282 | idtoname_hash(item)); | 281 | idtoname_hash(item)); |
| 283 | if (ch) | 282 | if (ch) |
| 284 | return container_of(ch, struct ent, h); | 283 | return container_of(ch, struct ent, h); |
| @@ -287,10 +286,9 @@ idtoname_lookup(struct ent *item) | |||
| 287 | } | 286 | } |
| 288 | 287 | ||
| 289 | static struct ent * | 288 | static struct ent * |
| 290 | idtoname_update(struct ent *new, struct ent *old) | 289 | idtoname_update(struct cache_detail *cd, struct ent *new, struct ent *old) |
| 291 | { | 290 | { |
| 292 | struct cache_head *ch = sunrpc_cache_update(&idtoname_cache, | 291 | struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h, |
| 293 | &new->h, &old->h, | ||
| 294 | idtoname_hash(new)); | 292 | idtoname_hash(new)); |
| 295 | if (ch) | 293 | if (ch) |
| 296 | return container_of(ch, struct ent, h); | 294 | return container_of(ch, struct ent, h); |
| @@ -303,8 +301,6 @@ idtoname_update(struct ent *new, struct ent *old) | |||
| 303 | * Name -> ID cache | 301 | * Name -> ID cache |
| 304 | */ | 302 | */ |
| 305 | 303 | ||
| 306 | static struct cache_head *nametoid_table[ENT_HASHMAX]; | ||
| 307 | |||
| 308 | static inline int | 304 | static inline int |
| 309 | nametoid_hash(struct ent *ent) | 305 | nametoid_hash(struct ent *ent) |
| 310 | { | 306 | { |
| @@ -359,14 +355,14 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) | |||
| 359 | return 0; | 355 | return 0; |
| 360 | } | 356 | } |
| 361 | 357 | ||
| 362 | static struct ent *nametoid_lookup(struct ent *); | 358 | static struct ent *nametoid_lookup(struct cache_detail *, struct ent *); |
| 363 | static struct ent *nametoid_update(struct ent *, struct ent *); | 359 | static struct ent *nametoid_update(struct cache_detail *, struct ent *, |
| 360 | struct ent *); | ||
| 364 | static int nametoid_parse(struct cache_detail *, char *, int); | 361 | static int nametoid_parse(struct cache_detail *, char *, int); |
| 365 | 362 | ||
| 366 | static struct cache_detail nametoid_cache = { | 363 | static struct cache_detail nametoid_cache_template = { |
| 367 | .owner = THIS_MODULE, | 364 | .owner = THIS_MODULE, |
| 368 | .hash_size = ENT_HASHMAX, | 365 | .hash_size = ENT_HASHMAX, |
| 369 | .hash_table = nametoid_table, | ||
| 370 | .name = "nfs4.nametoid", | 366 | .name = "nfs4.nametoid", |
| 371 | .cache_put = ent_put, | 367 | .cache_put = ent_put, |
| 372 | .cache_upcall = nametoid_upcall, | 368 | .cache_upcall = nametoid_upcall, |
| @@ -426,14 +422,14 @@ nametoid_parse(struct cache_detail *cd, char *buf, int buflen) | |||
| 426 | set_bit(CACHE_NEGATIVE, &ent.h.flags); | 422 | set_bit(CACHE_NEGATIVE, &ent.h.flags); |
| 427 | 423 | ||
| 428 | error = -ENOMEM; | 424 | error = -ENOMEM; |
| 429 | res = nametoid_lookup(&ent); | 425 | res = nametoid_lookup(cd, &ent); |
| 430 | if (res == NULL) | 426 | if (res == NULL) |
| 431 | goto out; | 427 | goto out; |
| 432 | res = nametoid_update(&ent, res); | 428 | res = nametoid_update(cd, &ent, res); |
| 433 | if (res == NULL) | 429 | if (res == NULL) |
| 434 | goto out; | 430 | goto out; |
| 435 | 431 | ||
| 436 | cache_put(&res->h, &nametoid_cache); | 432 | cache_put(&res->h, cd); |
| 437 | error = 0; | 433 | error = 0; |
| 438 | out: | 434 | out: |
| 439 | kfree(buf1); | 435 | kfree(buf1); |
| @@ -443,10 +439,9 @@ out: | |||
| 443 | 439 | ||
| 444 | 440 | ||
| 445 | static struct ent * | 441 | static struct ent * |
| 446 | nametoid_lookup(struct ent *item) | 442 | nametoid_lookup(struct cache_detail *cd, struct ent *item) |
| 447 | { | 443 | { |
| 448 | struct cache_head *ch = sunrpc_cache_lookup(&nametoid_cache, | 444 | struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h, |
| 449 | &item->h, | ||
| 450 | nametoid_hash(item)); | 445 | nametoid_hash(item)); |
| 451 | if (ch) | 446 | if (ch) |
| 452 | return container_of(ch, struct ent, h); | 447 | return container_of(ch, struct ent, h); |
| @@ -455,10 +450,9 @@ nametoid_lookup(struct ent *item) | |||
| 455 | } | 450 | } |
| 456 | 451 | ||
| 457 | static struct ent * | 452 | static struct ent * |
| 458 | nametoid_update(struct ent *new, struct ent *old) | 453 | nametoid_update(struct cache_detail *cd, struct ent *new, struct ent *old) |
| 459 | { | 454 | { |
| 460 | struct cache_head *ch = sunrpc_cache_update(&nametoid_cache, | 455 | struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h, |
| 461 | &new->h, &old->h, | ||
| 462 | nametoid_hash(new)); | 456 | nametoid_hash(new)); |
| 463 | if (ch) | 457 | if (ch) |
| 464 | return container_of(ch, struct ent, h); | 458 | return container_of(ch, struct ent, h); |
| @@ -471,34 +465,55 @@ nametoid_update(struct ent *new, struct ent *old) | |||
| 471 | */ | 465 | */ |
| 472 | 466 | ||
| 473 | int | 467 | int |
| 474 | nfsd_idmap_init(void) | 468 | nfsd_idmap_init(struct net *net) |
| 475 | { | 469 | { |
| 476 | int rv; | 470 | int rv; |
| 471 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 477 | 472 | ||
| 478 | rv = cache_register_net(&idtoname_cache, &init_net); | 473 | nn->idtoname_cache = cache_create_net(&idtoname_cache_template, net); |
| 474 | if (IS_ERR(nn->idtoname_cache)) | ||
| 475 | return PTR_ERR(nn->idtoname_cache); | ||
| 476 | rv = cache_register_net(nn->idtoname_cache, net); | ||
| 479 | if (rv) | 477 | if (rv) |
| 480 | return rv; | 478 | goto destroy_idtoname_cache; |
| 481 | rv = cache_register_net(&nametoid_cache, &init_net); | 479 | nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net); |
| 480 | if (IS_ERR(nn->nametoid_cache)) { | ||
| 481 | rv = PTR_ERR(nn->idtoname_cache); | ||
| 482 | goto unregister_idtoname_cache; | ||
| 483 | } | ||
| 484 | rv = cache_register_net(nn->nametoid_cache, net); | ||
| 482 | if (rv) | 485 | if (rv) |
| 483 | cache_unregister_net(&idtoname_cache, &init_net); | 486 | goto destroy_nametoid_cache; |
| 487 | return 0; | ||
| 488 | |||
| 489 | destroy_nametoid_cache: | ||
| 490 | cache_destroy_net(nn->nametoid_cache, net); | ||
| 491 | unregister_idtoname_cache: | ||
| 492 | cache_unregister_net(nn->idtoname_cache, net); | ||
| 493 | destroy_idtoname_cache: | ||
| 494 | cache_destroy_net(nn->idtoname_cache, net); | ||
| 484 | return rv; | 495 | return rv; |
| 485 | } | 496 | } |
| 486 | 497 | ||
| 487 | void | 498 | void |
| 488 | nfsd_idmap_shutdown(void) | 499 | nfsd_idmap_shutdown(struct net *net) |
| 489 | { | 500 | { |
| 490 | cache_unregister_net(&idtoname_cache, &init_net); | 501 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 491 | cache_unregister_net(&nametoid_cache, &init_net); | 502 | |
| 503 | cache_unregister_net(nn->idtoname_cache, net); | ||
| 504 | cache_unregister_net(nn->nametoid_cache, net); | ||
| 505 | cache_destroy_net(nn->idtoname_cache, net); | ||
| 506 | cache_destroy_net(nn->nametoid_cache, net); | ||
| 492 | } | 507 | } |
| 493 | 508 | ||
| 494 | static int | 509 | static int |
| 495 | idmap_lookup(struct svc_rqst *rqstp, | 510 | idmap_lookup(struct svc_rqst *rqstp, |
| 496 | struct ent *(*lookup_fn)(struct ent *), struct ent *key, | 511 | struct ent *(*lookup_fn)(struct cache_detail *, struct ent *), |
| 497 | struct cache_detail *detail, struct ent **item) | 512 | struct ent *key, struct cache_detail *detail, struct ent **item) |
| 498 | { | 513 | { |
| 499 | int ret; | 514 | int ret; |
| 500 | 515 | ||
| 501 | *item = lookup_fn(key); | 516 | *item = lookup_fn(detail, key); |
| 502 | if (!*item) | 517 | if (!*item) |
| 503 | return -ENOMEM; | 518 | return -ENOMEM; |
| 504 | retry: | 519 | retry: |
| @@ -506,7 +521,7 @@ idmap_lookup(struct svc_rqst *rqstp, | |||
| 506 | 521 | ||
| 507 | if (ret == -ETIMEDOUT) { | 522 | if (ret == -ETIMEDOUT) { |
| 508 | struct ent *prev_item = *item; | 523 | struct ent *prev_item = *item; |
| 509 | *item = lookup_fn(key); | 524 | *item = lookup_fn(detail, key); |
| 510 | if (*item != prev_item) | 525 | if (*item != prev_item) |
| 511 | goto retry; | 526 | goto retry; |
| 512 | cache_put(&(*item)->h, detail); | 527 | cache_put(&(*item)->h, detail); |
| @@ -531,19 +546,20 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen | |||
| 531 | .type = type, | 546 | .type = type, |
| 532 | }; | 547 | }; |
| 533 | int ret; | 548 | int ret; |
| 549 | struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); | ||
| 534 | 550 | ||
| 535 | if (namelen + 1 > sizeof(key.name)) | 551 | if (namelen + 1 > sizeof(key.name)) |
| 536 | return nfserr_badowner; | 552 | return nfserr_badowner; |
| 537 | memcpy(key.name, name, namelen); | 553 | memcpy(key.name, name, namelen); |
| 538 | key.name[namelen] = '\0'; | 554 | key.name[namelen] = '\0'; |
| 539 | strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); | 555 | strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); |
| 540 | ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); | 556 | ret = idmap_lookup(rqstp, nametoid_lookup, &key, nn->nametoid_cache, &item); |
| 541 | if (ret == -ENOENT) | 557 | if (ret == -ENOENT) |
| 542 | return nfserr_badowner; | 558 | return nfserr_badowner; |
| 543 | if (ret) | 559 | if (ret) |
| 544 | return nfserrno(ret); | 560 | return nfserrno(ret); |
| 545 | *id = item->id; | 561 | *id = item->id; |
| 546 | cache_put(&item->h, &nametoid_cache); | 562 | cache_put(&item->h, nn->nametoid_cache); |
| 547 | return 0; | 563 | return 0; |
| 548 | } | 564 | } |
| 549 | 565 | ||
| @@ -555,9 +571,10 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) | |||
| 555 | .type = type, | 571 | .type = type, |
| 556 | }; | 572 | }; |
| 557 | int ret; | 573 | int ret; |
| 574 | struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); | ||
| 558 | 575 | ||
| 559 | strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); | 576 | strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); |
| 560 | ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item); | 577 | ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item); |
| 561 | if (ret == -ENOENT) | 578 | if (ret == -ENOENT) |
| 562 | return sprintf(name, "%u", id); | 579 | return sprintf(name, "%u", id); |
| 563 | if (ret) | 580 | if (ret) |
| @@ -565,7 +582,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) | |||
| 565 | ret = strlen(item->name); | 582 | ret = strlen(item->name); |
| 566 | BUG_ON(ret > IDMAP_NAMESZ); | 583 | BUG_ON(ret > IDMAP_NAMESZ); |
| 567 | memcpy(name, item->name, ret); | 584 | memcpy(name, item->name, ret); |
| 568 | cache_put(&item->h, &idtoname_cache); | 585 | cache_put(&item->h, nn->idtoname_cache); |
| 569 | return ret; | 586 | return ret; |
| 570 | } | 587 | } |
| 571 | 588 | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7f71c69cdcdf..03f82c0bc35d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -3155,10 +3155,17 @@ out: | |||
| 3155 | static struct lock_manager nfsd4_manager = { | 3155 | static struct lock_manager nfsd4_manager = { |
| 3156 | }; | 3156 | }; |
| 3157 | 3157 | ||
| 3158 | static bool grace_ended; | ||
| 3159 | |||
| 3158 | static void | 3160 | static void |
| 3159 | nfsd4_end_grace(void) | 3161 | nfsd4_end_grace(void) |
| 3160 | { | 3162 | { |
| 3163 | /* do nothing if grace period already ended */ | ||
| 3164 | if (grace_ended) | ||
| 3165 | return; | ||
| 3166 | |||
| 3161 | dprintk("NFSD: end of grace period\n"); | 3167 | dprintk("NFSD: end of grace period\n"); |
| 3168 | grace_ended = true; | ||
| 3162 | nfsd4_record_grace_done(&init_net, boot_time); | 3169 | nfsd4_record_grace_done(&init_net, boot_time); |
| 3163 | locks_end_grace(&nfsd4_manager); | 3170 | locks_end_grace(&nfsd4_manager); |
| 3164 | /* | 3171 | /* |
| @@ -3183,8 +3190,7 @@ nfs4_laundromat(void) | |||
| 3183 | nfs4_lock_state(); | 3190 | nfs4_lock_state(); |
| 3184 | 3191 | ||
| 3185 | dprintk("NFSD: laundromat service - starting\n"); | 3192 | dprintk("NFSD: laundromat service - starting\n"); |
| 3186 | if (locks_in_grace()) | 3193 | nfsd4_end_grace(); |
| 3187 | nfsd4_end_grace(); | ||
| 3188 | INIT_LIST_HEAD(&reaplist); | 3194 | INIT_LIST_HEAD(&reaplist); |
| 3189 | spin_lock(&client_lock); | 3195 | spin_lock(&client_lock); |
| 3190 | list_for_each_safe(pos, next, &client_lru) { | 3196 | list_for_each_safe(pos, next, &client_lru) { |
| @@ -4055,7 +4061,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4055 | struct nfs4_openowner *open_sop = NULL; | 4061 | struct nfs4_openowner *open_sop = NULL; |
| 4056 | struct nfs4_lockowner *lock_sop = NULL; | 4062 | struct nfs4_lockowner *lock_sop = NULL; |
| 4057 | struct nfs4_ol_stateid *lock_stp; | 4063 | struct nfs4_ol_stateid *lock_stp; |
| 4058 | struct nfs4_file *fp; | ||
| 4059 | struct file *filp = NULL; | 4064 | struct file *filp = NULL; |
| 4060 | struct file_lock file_lock; | 4065 | struct file_lock file_lock; |
| 4061 | struct file_lock conflock; | 4066 | struct file_lock conflock; |
| @@ -4123,7 +4128,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4123 | goto out; | 4128 | goto out; |
| 4124 | } | 4129 | } |
| 4125 | lock_sop = lockowner(lock_stp->st_stateowner); | 4130 | lock_sop = lockowner(lock_stp->st_stateowner); |
| 4126 | fp = lock_stp->st_file; | ||
| 4127 | 4131 | ||
| 4128 | lkflg = setlkflg(lock->lk_type); | 4132 | lkflg = setlkflg(lock->lk_type); |
| 4129 | status = nfs4_check_openmode(lock_stp, lkflg); | 4133 | status = nfs4_check_openmode(lock_stp, lkflg); |
| @@ -4715,6 +4719,7 @@ nfs4_state_start(void) | |||
| 4715 | nfsd4_client_tracking_init(&init_net); | 4719 | nfsd4_client_tracking_init(&init_net); |
| 4716 | boot_time = get_seconds(); | 4720 | boot_time = get_seconds(); |
| 4717 | locks_start_grace(&nfsd4_manager); | 4721 | locks_start_grace(&nfsd4_manager); |
| 4722 | grace_ended = false; | ||
| 4718 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 4723 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", |
| 4719 | nfsd4_grace); | 4724 | nfsd4_grace); |
| 4720 | ret = set_callback_cred(); | 4725 | ret = set_callback_cred(); |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 2c53be6d3579..72699885ac48 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
| @@ -127,7 +127,17 @@ static const struct file_operations transaction_ops = { | |||
| 127 | 127 | ||
| 128 | static int exports_open(struct inode *inode, struct file *file) | 128 | static int exports_open(struct inode *inode, struct file *file) |
| 129 | { | 129 | { |
| 130 | return seq_open(file, &nfs_exports_op); | 130 | int err; |
| 131 | struct seq_file *seq; | ||
| 132 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
| 133 | |||
| 134 | err = seq_open(file, &nfs_exports_op); | ||
| 135 | if (err) | ||
| 136 | return err; | ||
| 137 | |||
| 138 | seq = file->private_data; | ||
| 139 | seq->private = nn->svc_export_cache; | ||
| 140 | return 0; | ||
| 131 | } | 141 | } |
| 132 | 142 | ||
| 133 | static const struct file_operations exports_operations = { | 143 | static const struct file_operations exports_operations = { |
| @@ -345,7 +355,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size) | |||
| 345 | if (!dom) | 355 | if (!dom) |
| 346 | return -ENOMEM; | 356 | return -ENOMEM; |
| 347 | 357 | ||
| 348 | len = exp_rootfh(dom, path, &fh, maxsize); | 358 | len = exp_rootfh(&init_net, dom, path, &fh, maxsize); |
| 349 | auth_domain_put(dom); | 359 | auth_domain_put(dom); |
| 350 | if (len) | 360 | if (len) |
| 351 | return len; | 361 | return len; |
| @@ -1127,7 +1137,34 @@ static int create_proc_exports_entry(void) | |||
| 1127 | #endif | 1137 | #endif |
| 1128 | 1138 | ||
| 1129 | int nfsd_net_id; | 1139 | int nfsd_net_id; |
| 1140 | |||
| 1141 | static __net_init int nfsd_init_net(struct net *net) | ||
| 1142 | { | ||
| 1143 | int retval; | ||
| 1144 | |||
| 1145 | retval = nfsd_export_init(net); | ||
| 1146 | if (retval) | ||
| 1147 | goto out_export_error; | ||
| 1148 | retval = nfsd_idmap_init(net); | ||
| 1149 | if (retval) | ||
| 1150 | goto out_idmap_error; | ||
| 1151 | return 0; | ||
| 1152 | |||
| 1153 | out_idmap_error: | ||
| 1154 | nfsd_export_shutdown(net); | ||
| 1155 | out_export_error: | ||
| 1156 | return retval; | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | static __net_exit void nfsd_exit_net(struct net *net) | ||
| 1160 | { | ||
| 1161 | nfsd_idmap_shutdown(net); | ||
| 1162 | nfsd_export_shutdown(net); | ||
| 1163 | } | ||
| 1164 | |||
| 1130 | static struct pernet_operations nfsd_net_ops = { | 1165 | static struct pernet_operations nfsd_net_ops = { |
| 1166 | .init = nfsd_init_net, | ||
| 1167 | .exit = nfsd_exit_net, | ||
| 1131 | .id = &nfsd_net_id, | 1168 | .id = &nfsd_net_id, |
| 1132 | .size = sizeof(struct nfsd_net), | 1169 | .size = sizeof(struct nfsd_net), |
| 1133 | }; | 1170 | }; |
| @@ -1154,16 +1191,10 @@ static int __init init_nfsd(void) | |||
| 1154 | retval = nfsd_reply_cache_init(); | 1191 | retval = nfsd_reply_cache_init(); |
| 1155 | if (retval) | 1192 | if (retval) |
| 1156 | goto out_free_stat; | 1193 | goto out_free_stat; |
| 1157 | retval = nfsd_export_init(); | ||
| 1158 | if (retval) | ||
| 1159 | goto out_free_cache; | ||
| 1160 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ | 1194 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ |
| 1161 | retval = nfsd_idmap_init(); | ||
| 1162 | if (retval) | ||
| 1163 | goto out_free_lockd; | ||
| 1164 | retval = create_proc_exports_entry(); | 1195 | retval = create_proc_exports_entry(); |
| 1165 | if (retval) | 1196 | if (retval) |
| 1166 | goto out_free_idmap; | 1197 | goto out_free_lockd; |
| 1167 | retval = register_filesystem(&nfsd_fs_type); | 1198 | retval = register_filesystem(&nfsd_fs_type); |
| 1168 | if (retval) | 1199 | if (retval) |
| 1169 | goto out_free_all; | 1200 | goto out_free_all; |
| @@ -1171,12 +1202,8 @@ static int __init init_nfsd(void) | |||
| 1171 | out_free_all: | 1202 | out_free_all: |
| 1172 | remove_proc_entry("fs/nfs/exports", NULL); | 1203 | remove_proc_entry("fs/nfs/exports", NULL); |
| 1173 | remove_proc_entry("fs/nfs", NULL); | 1204 | remove_proc_entry("fs/nfs", NULL); |
| 1174 | out_free_idmap: | ||
| 1175 | nfsd_idmap_shutdown(); | ||
| 1176 | out_free_lockd: | 1205 | out_free_lockd: |
| 1177 | nfsd_lockd_shutdown(); | 1206 | nfsd_lockd_shutdown(); |
| 1178 | nfsd_export_shutdown(); | ||
| 1179 | out_free_cache: | ||
| 1180 | nfsd_reply_cache_shutdown(); | 1207 | nfsd_reply_cache_shutdown(); |
| 1181 | out_free_stat: | 1208 | out_free_stat: |
| 1182 | nfsd_stat_shutdown(); | 1209 | nfsd_stat_shutdown(); |
| @@ -1192,13 +1219,11 @@ out_unregister_notifier: | |||
| 1192 | 1219 | ||
| 1193 | static void __exit exit_nfsd(void) | 1220 | static void __exit exit_nfsd(void) |
| 1194 | { | 1221 | { |
| 1195 | nfsd_export_shutdown(); | ||
| 1196 | nfsd_reply_cache_shutdown(); | 1222 | nfsd_reply_cache_shutdown(); |
| 1197 | remove_proc_entry("fs/nfs/exports", NULL); | 1223 | remove_proc_entry("fs/nfs/exports", NULL); |
| 1198 | remove_proc_entry("fs/nfs", NULL); | 1224 | remove_proc_entry("fs/nfs", NULL); |
| 1199 | nfsd_stat_shutdown(); | 1225 | nfsd_stat_shutdown(); |
| 1200 | nfsd_lockd_shutdown(); | 1226 | nfsd_lockd_shutdown(); |
| 1201 | nfsd_idmap_shutdown(); | ||
| 1202 | nfsd4_free_slabs(); | 1227 | nfsd4_free_slabs(); |
| 1203 | nfsd_fault_inject_cleanup(); | 1228 | nfsd_fault_inject_cleanup(); |
| 1204 | unregister_filesystem(&nfsd_fs_type); | 1229 | unregister_filesystem(&nfsd_fs_type); |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 68454e75fce9..cc793005a87c 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
| @@ -636,7 +636,7 @@ fh_put(struct svc_fh *fhp) | |||
| 636 | #endif | 636 | #endif |
| 637 | } | 637 | } |
| 638 | if (exp) { | 638 | if (exp) { |
| 639 | cache_put(&exp->h, &svc_export_cache); | 639 | exp_put(exp); |
| 640 | fhp->fh_export = NULL; | 640 | fhp->fh_export = NULL; |
| 641 | } | 641 | } |
| 642 | return; | 642 | return; |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 28dfad39f0c5..cb4d51d8cbdb 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
| @@ -220,7 +220,7 @@ static int nfsd_startup(unsigned short port, int nrservs) | |||
| 220 | ret = nfsd_init_socks(port); | 220 | ret = nfsd_init_socks(port); |
| 221 | if (ret) | 221 | if (ret) |
| 222 | goto out_racache; | 222 | goto out_racache; |
| 223 | ret = lockd_up(); | 223 | ret = lockd_up(&init_net); |
| 224 | if (ret) | 224 | if (ret) |
| 225 | goto out_racache; | 225 | goto out_racache; |
| 226 | ret = nfs4_state_start(); | 226 | ret = nfs4_state_start(); |
| @@ -229,7 +229,7 @@ static int nfsd_startup(unsigned short port, int nrservs) | |||
| 229 | nfsd_up = true; | 229 | nfsd_up = true; |
| 230 | return 0; | 230 | return 0; |
| 231 | out_lockd: | 231 | out_lockd: |
| 232 | lockd_down(); | 232 | lockd_down(&init_net); |
| 233 | out_racache: | 233 | out_racache: |
| 234 | nfsd_racache_shutdown(); | 234 | nfsd_racache_shutdown(); |
| 235 | return ret; | 235 | return ret; |
| @@ -246,7 +246,7 @@ static void nfsd_shutdown(void) | |||
| 246 | if (!nfsd_up) | 246 | if (!nfsd_up) |
| 247 | return; | 247 | return; |
| 248 | nfs4_state_shutdown(); | 248 | nfs4_state_shutdown(); |
| 249 | lockd_down(); | 249 | lockd_down(&init_net); |
| 250 | nfsd_racache_shutdown(); | 250 | nfsd_racache_shutdown(); |
| 251 | nfsd_up = false; | 251 | nfsd_up = false; |
| 252 | } | 252 | } |
| @@ -261,7 +261,7 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net) | |||
| 261 | 261 | ||
| 262 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " | 262 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " |
| 263 | "cache\n"); | 263 | "cache\n"); |
| 264 | nfsd_export_flush(); | 264 | nfsd_export_flush(net); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | void nfsd_reset_versions(void) | 267 | void nfsd_reset_versions(void) |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 568666156ea4..c8bd9c3be7f7 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -2039,7 +2039,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, | |||
| 2039 | if (err) | 2039 | if (err) |
| 2040 | goto out; | 2040 | goto out; |
| 2041 | 2041 | ||
| 2042 | offset = vfs_llseek(file, offset, 0); | 2042 | offset = vfs_llseek(file, offset, SEEK_SET); |
| 2043 | if (offset < 0) { | 2043 | if (offset < 0) { |
| 2044 | err = nfserrno((int)offset); | 2044 | err = nfserrno((int)offset); |
| 2045 | goto out_close; | 2045 | goto out_close; |
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index 11a966e5f829..4d24d64578c4 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h | |||
| @@ -54,7 +54,7 @@ extern void nlmclnt_done(struct nlm_host *host); | |||
| 54 | 54 | ||
| 55 | extern int nlmclnt_proc(struct nlm_host *host, int cmd, | 55 | extern int nlmclnt_proc(struct nlm_host *host, int cmd, |
| 56 | struct file_lock *fl); | 56 | struct file_lock *fl); |
| 57 | extern int lockd_up(void); | 57 | extern int lockd_up(struct net *net); |
| 58 | extern void lockd_down(void); | 58 | extern void lockd_down(struct net *net); |
| 59 | 59 | ||
| 60 | #endif /* LINUX_LOCKD_BIND_H */ | 60 | #endif /* LINUX_LOCKD_BIND_H */ |
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index f85308e688fd..e33f747b173c 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h | |||
| @@ -103,6 +103,7 @@ struct svc_export { | |||
| 103 | struct nfsd4_fs_locations ex_fslocs; | 103 | struct nfsd4_fs_locations ex_fslocs; |
| 104 | int ex_nflavors; | 104 | int ex_nflavors; |
| 105 | struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST]; | 105 | struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST]; |
| 106 | struct cache_detail *cd; | ||
| 106 | }; | 107 | }; |
| 107 | 108 | ||
| 108 | /* an "export key" (expkey) maps a filehandlefragement to an | 109 | /* 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); | |||
| 129 | /* | 130 | /* |
| 130 | * Function declarations | 131 | * Function declarations |
| 131 | */ | 132 | */ |
| 132 | int nfsd_export_init(void); | 133 | int nfsd_export_init(struct net *); |
| 133 | void nfsd_export_shutdown(void); | 134 | void nfsd_export_shutdown(struct net *); |
| 134 | void nfsd_export_flush(void); | 135 | void nfsd_export_flush(struct net *); |
| 135 | struct svc_export * rqst_exp_get_by_name(struct svc_rqst *, | 136 | struct svc_export * rqst_exp_get_by_name(struct svc_rqst *, |
| 136 | struct path *); | 137 | struct path *); |
| 137 | struct svc_export * rqst_exp_parent(struct svc_rqst *, | 138 | struct svc_export * rqst_exp_parent(struct svc_rqst *, |
| 138 | struct path *); | 139 | struct path *); |
| 139 | struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *); | 140 | struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *); |
| 140 | int exp_rootfh(struct auth_domain *, | 141 | int exp_rootfh(struct net *, struct auth_domain *, |
| 141 | char *path, struct knfsd_fh *, int maxsize); | 142 | char *path, struct knfsd_fh *, int maxsize); |
| 142 | __be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *); | 143 | __be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *); |
| 143 | __be32 nfserrno(int errno); | 144 | __be32 nfserrno(int errno); |
| 144 | 145 | ||
| 145 | extern struct cache_detail svc_export_cache; | ||
| 146 | |||
| 147 | static inline void exp_put(struct svc_export *exp) | 146 | static inline void exp_put(struct svc_export *exp) |
| 148 | { | 147 | { |
| 149 | cache_put(&exp->h, &svc_export_cache); | 148 | cache_put(&exp->h, exp->cd); |
| 150 | } | 149 | } |
| 151 | 150 | ||
| 152 | static inline void exp_get(struct svc_export *exp) | 151 | static inline void exp_get(struct svc_export *exp) |
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index 548790e9113b..2c54683b91de 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h | |||
| @@ -16,7 +16,6 @@ | |||
| 16 | #include <linux/sunrpc/cache.h> | 16 | #include <linux/sunrpc/cache.h> |
| 17 | #include <linux/hash.h> | 17 | #include <linux/hash.h> |
| 18 | 18 | ||
| 19 | #define SVC_CRED_NGROUPS 32 | ||
| 20 | struct svc_cred { | 19 | struct svc_cred { |
| 21 | uid_t cr_uid; | 20 | uid_t cr_uid; |
| 22 | gid_t cr_gid; | 21 | gid_t cr_gid; |
| @@ -131,7 +130,7 @@ extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *ne | |||
| 131 | extern struct auth_domain *auth_domain_find(char *name); | 130 | extern struct auth_domain *auth_domain_find(char *name); |
| 132 | extern struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr); | 131 | extern struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr); |
| 133 | extern int auth_unix_forget_old(struct auth_domain *dom); | 132 | extern int auth_unix_forget_old(struct auth_domain *dom); |
| 134 | extern void svcauth_unix_purge(void); | 133 | extern void svcauth_unix_purge(struct net *net); |
| 135 | extern void svcauth_unix_info_release(struct svc_xprt *xpt); | 134 | extern void svcauth_unix_info_release(struct svc_xprt *xpt); |
| 136 | extern int svcauth_unix_set_client(struct svc_rqst *rqstp); | 135 | extern int svcauth_unix_set_client(struct svc_rqst *rqstp); |
| 137 | 136 | ||
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 28b62dbb6d1e..3089de37c433 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
| @@ -969,16 +969,17 @@ svcauth_gss_set_client(struct svc_rqst *rqstp) | |||
| 969 | } | 969 | } |
| 970 | 970 | ||
| 971 | static inline int | 971 | static inline int |
| 972 | gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi *rsip) | 972 | gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, |
| 973 | struct xdr_netobj *out_handle, int *major_status) | ||
| 973 | { | 974 | { |
| 974 | struct rsc *rsci; | 975 | struct rsc *rsci; |
| 975 | int rc; | 976 | int rc; |
| 976 | 977 | ||
| 977 | if (rsip->major_status != GSS_S_COMPLETE) | 978 | if (*major_status != GSS_S_COMPLETE) |
| 978 | return gss_write_null_verf(rqstp); | 979 | return gss_write_null_verf(rqstp); |
| 979 | rsci = gss_svc_searchbyctx(cd, &rsip->out_handle); | 980 | rsci = gss_svc_searchbyctx(cd, out_handle); |
| 980 | if (rsci == NULL) { | 981 | if (rsci == NULL) { |
| 981 | rsip->major_status = GSS_S_NO_CONTEXT; | 982 | *major_status = GSS_S_NO_CONTEXT; |
| 982 | return gss_write_null_verf(rqstp); | 983 | return gss_write_null_verf(rqstp); |
| 983 | } | 984 | } |
| 984 | rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN); | 985 | rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN); |
| @@ -986,22 +987,13 @@ gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi | |||
| 986 | return rc; | 987 | return rc; |
| 987 | } | 988 | } |
| 988 | 989 | ||
| 989 | /* | 990 | static inline int |
| 990 | * Having read the cred already and found we're in the context | 991 | gss_read_verf(struct rpc_gss_wire_cred *gc, |
| 991 | * initiation case, read the verifier and initiate (or check the results | 992 | struct kvec *argv, __be32 *authp, |
| 992 | * of) upcalls to userspace for help with context initiation. If | 993 | struct xdr_netobj *in_handle, |
| 993 | * the upcall results are available, write the verifier and result. | 994 | struct xdr_netobj *in_token) |
| 994 | * Otherwise, drop the request pending an answer to the upcall. | ||
| 995 | */ | ||
| 996 | static int svcauth_gss_handle_init(struct svc_rqst *rqstp, | ||
| 997 | struct rpc_gss_wire_cred *gc, __be32 *authp) | ||
| 998 | { | 995 | { |
| 999 | struct kvec *argv = &rqstp->rq_arg.head[0]; | ||
| 1000 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
| 1001 | struct xdr_netobj tmpobj; | 996 | struct xdr_netobj tmpobj; |
| 1002 | struct rsi *rsip, rsikey; | ||
| 1003 | int ret; | ||
| 1004 | struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id); | ||
| 1005 | 997 | ||
| 1006 | /* Read the verifier; should be NULL: */ | 998 | /* Read the verifier; should be NULL: */ |
| 1007 | *authp = rpc_autherr_badverf; | 999 | *authp = rpc_autherr_badverf; |
| @@ -1011,24 +1003,67 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp, | |||
| 1011 | return SVC_DENIED; | 1003 | return SVC_DENIED; |
| 1012 | if (svc_getnl(argv) != 0) | 1004 | if (svc_getnl(argv) != 0) |
| 1013 | return SVC_DENIED; | 1005 | return SVC_DENIED; |
| 1014 | |||
| 1015 | /* Martial context handle and token for upcall: */ | 1006 | /* Martial context handle and token for upcall: */ |
| 1016 | *authp = rpc_autherr_badcred; | 1007 | *authp = rpc_autherr_badcred; |
| 1017 | if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0) | 1008 | if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0) |
| 1018 | return SVC_DENIED; | 1009 | return SVC_DENIED; |
| 1019 | memset(&rsikey, 0, sizeof(rsikey)); | 1010 | if (dup_netobj(in_handle, &gc->gc_ctx)) |
| 1020 | if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx)) | ||
| 1021 | return SVC_CLOSE; | 1011 | return SVC_CLOSE; |
| 1022 | *authp = rpc_autherr_badverf; | 1012 | *authp = rpc_autherr_badverf; |
| 1023 | if (svc_safe_getnetobj(argv, &tmpobj)) { | 1013 | if (svc_safe_getnetobj(argv, &tmpobj)) { |
| 1024 | kfree(rsikey.in_handle.data); | 1014 | kfree(in_handle->data); |
| 1025 | return SVC_DENIED; | 1015 | return SVC_DENIED; |
| 1026 | } | 1016 | } |
| 1027 | if (dup_netobj(&rsikey.in_token, &tmpobj)) { | 1017 | if (dup_netobj(in_token, &tmpobj)) { |
| 1028 | kfree(rsikey.in_handle.data); | 1018 | kfree(in_handle->data); |
| 1029 | return SVC_CLOSE; | 1019 | return SVC_CLOSE; |
| 1030 | } | 1020 | } |
| 1031 | 1021 | ||
| 1022 | return 0; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | static inline int | ||
| 1026 | gss_write_resv(struct kvec *resv, size_t size_limit, | ||
| 1027 | struct xdr_netobj *out_handle, struct xdr_netobj *out_token, | ||
| 1028 | int major_status, int minor_status) | ||
| 1029 | { | ||
| 1030 | if (resv->iov_len + 4 > size_limit) | ||
| 1031 | return -1; | ||
| 1032 | svc_putnl(resv, RPC_SUCCESS); | ||
| 1033 | if (svc_safe_putnetobj(resv, out_handle)) | ||
| 1034 | return -1; | ||
| 1035 | if (resv->iov_len + 3 * 4 > size_limit) | ||
| 1036 | return -1; | ||
| 1037 | svc_putnl(resv, major_status); | ||
| 1038 | svc_putnl(resv, minor_status); | ||
| 1039 | svc_putnl(resv, GSS_SEQ_WIN); | ||
| 1040 | if (svc_safe_putnetobj(resv, out_token)) | ||
| 1041 | return -1; | ||
| 1042 | return 0; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | /* | ||
| 1046 | * Having read the cred already and found we're in the context | ||
| 1047 | * initiation case, read the verifier and initiate (or check the results | ||
| 1048 | * of) upcalls to userspace for help with context initiation. If | ||
| 1049 | * the upcall results are available, write the verifier and result. | ||
| 1050 | * Otherwise, drop the request pending an answer to the upcall. | ||
| 1051 | */ | ||
| 1052 | static int svcauth_gss_handle_init(struct svc_rqst *rqstp, | ||
| 1053 | struct rpc_gss_wire_cred *gc, __be32 *authp) | ||
| 1054 | { | ||
| 1055 | struct kvec *argv = &rqstp->rq_arg.head[0]; | ||
| 1056 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
| 1057 | struct rsi *rsip, rsikey; | ||
| 1058 | int ret; | ||
| 1059 | struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id); | ||
| 1060 | |||
| 1061 | memset(&rsikey, 0, sizeof(rsikey)); | ||
| 1062 | ret = gss_read_verf(gc, argv, authp, | ||
| 1063 | &rsikey.in_handle, &rsikey.in_token); | ||
| 1064 | if (ret) | ||
| 1065 | return ret; | ||
| 1066 | |||
| 1032 | /* Perform upcall, or find upcall result: */ | 1067 | /* Perform upcall, or find upcall result: */ |
| 1033 | rsip = rsi_lookup(sn->rsi_cache, &rsikey); | 1068 | rsip = rsi_lookup(sn->rsi_cache, &rsikey); |
| 1034 | rsi_free(&rsikey); | 1069 | rsi_free(&rsikey); |
| @@ -1040,19 +1075,12 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp, | |||
| 1040 | 1075 | ||
| 1041 | ret = SVC_CLOSE; | 1076 | ret = SVC_CLOSE; |
| 1042 | /* Got an answer to the upcall; use it: */ | 1077 | /* Got an answer to the upcall; use it: */ |
| 1043 | if (gss_write_init_verf(sn->rsc_cache, rqstp, rsip)) | 1078 | if (gss_write_init_verf(sn->rsc_cache, rqstp, |
| 1079 | &rsip->out_handle, &rsip->major_status)) | ||
| 1044 | goto out; | 1080 | goto out; |
| 1045 | if (resv->iov_len + 4 > PAGE_SIZE) | 1081 | if (gss_write_resv(resv, PAGE_SIZE, |
| 1046 | goto out; | 1082 | &rsip->out_handle, &rsip->out_token, |
| 1047 | svc_putnl(resv, RPC_SUCCESS); | 1083 | rsip->major_status, rsip->minor_status)) |
| 1048 | if (svc_safe_putnetobj(resv, &rsip->out_handle)) | ||
| 1049 | goto out; | ||
| 1050 | if (resv->iov_len + 3 * 4 > PAGE_SIZE) | ||
| 1051 | goto out; | ||
| 1052 | svc_putnl(resv, rsip->major_status); | ||
| 1053 | svc_putnl(resv, rsip->minor_status); | ||
| 1054 | svc_putnl(resv, GSS_SEQ_WIN); | ||
| 1055 | if (svc_safe_putnetobj(resv, &rsip->out_token)) | ||
| 1056 | goto out; | 1084 | goto out; |
| 1057 | 1085 | ||
| 1058 | ret = SVC_COMPLETE; | 1086 | ret = SVC_COMPLETE; |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 71ec8530ec8c..6138c925923d 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
| @@ -347,17 +347,12 @@ static inline int ip_map_update(struct net *net, struct ip_map *ipm, | |||
| 347 | return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry); | 347 | return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry); |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | 350 | void svcauth_unix_purge(struct net *net) | |
| 351 | void svcauth_unix_purge(void) | ||
| 352 | { | 351 | { |
| 353 | struct net *net; | 352 | struct sunrpc_net *sn; |
| 354 | |||
| 355 | for_each_net(net) { | ||
| 356 | struct sunrpc_net *sn; | ||
| 357 | 353 | ||
| 358 | sn = net_generic(net, sunrpc_net_id); | 354 | sn = net_generic(net, sunrpc_net_id); |
| 359 | cache_purge(sn->ip_map_cache); | 355 | cache_purge(sn->ip_map_cache); |
| 360 | } | ||
| 361 | } | 356 | } |
| 362 | EXPORT_SYMBOL_GPL(svcauth_unix_purge); | 357 | EXPORT_SYMBOL_GPL(svcauth_unix_purge); |
| 363 | 358 | ||
