aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/idmap.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-23 11:53:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-23 11:53:47 -0400
commitf63d395d47f37a4fe771e6d4b1db9d2cdae5ffc5 (patch)
tree3448a14ae965802adb963762cadeb9989ce4caa2 /fs/nfs/idmap.c
parent643ac9fc5429e85b8b7f534544b80bcc4f34c367 (diff)
parent5a7c9eec9fde1da0e3adf0a4ddb64ff2a324a492 (diff)
Merge tag 'nfs-for-3.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates for Linux 3.4 from Trond Myklebust: "New features include: - Add NFS client support for containers. This should enable most of the necessary functionality, including lockd support, and support for rpc.statd, NFSv4 idmapper and RPCSEC_GSS upcalls into the correct network namespace from which the mount system call was issued. - NFSv4 idmapper scalability improvements Base the idmapper cache on the keyring interface to allow concurrent access to idmapper entries. Start the process of migrating users from the single-threaded daemon-based approach to the multi-threaded request-key based approach. - NFSv4.1 implementation id. Allows the NFSv4.1 client and server to mutually identify each other for logging and debugging purposes. - Support the 'vers=4.1' mount option for mounting NFSv4.1 instead of having to use the more counterintuitive 'vers=4,minorversion=1'. - SUNRPC tracepoints. Start the process of adding tracepoints in order to improve debugging of the RPC layer. - pNFS object layout support for autologin. Important bugfixes include: - Fix a bug in rpc_wake_up/rpc_wake_up_status that caused them to fail to wake up all tasks when applied to priority waitqueues. - Ensure that we handle read delegations correctly, when we try to truncate a file. - A number of fixes for NFSv4 state manager loops (mostly to do with delegation recovery)." * tag 'nfs-for-3.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (224 commits) NFS: fix sb->s_id in nfs debug prints xprtrdma: Remove assumption that each segment is <= PAGE_SIZE xprtrdma: The transport should not bug-check when a dup reply is received pnfs-obj: autologin: Add support for protocol autologin NFS: Remove nfs4_setup_sequence from generic rename code NFS: Remove nfs4_setup_sequence from generic unlink code NFS: Remove nfs4_setup_sequence from generic read code NFS: Remove nfs4_setup_sequence from generic write code NFS: Fix more NFS debug related build warnings SUNRPC/LOCKD: Fix build warnings when CONFIG_SUNRPC_DEBUG is undefined nfs: non void functions must return a value SUNRPC: Kill compiler warning when RPC_DEBUG is unset SUNRPC/NFS: Add Kbuild dependencies for NFS_DEBUG/RPC_DEBUG NFS: Use cond_resched_lock() to reduce latencies in the commit scans NFSv4: It is not safe to dereference lsp->ls_state in release_lockowner NFS: ncommit count is being double decremented SUNRPC: We must not use list_for_each_entry_safe() in rpc_wake_up() Try using machine credentials for RENEW calls NFSv4.1: Fix a few issues in filelayout_commit_pagelist NFSv4.1: Clean ups and bugfixes for the pNFS read/writeback/commit code ...
Diffstat (limited to 'fs/nfs/idmap.c')
-rw-r--r--fs/nfs/idmap.c733
1 files changed, 344 insertions, 389 deletions
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index a1bbf7780dfc..b7f348bb618b 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -34,11 +34,29 @@
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */ 35 */
36#include <linux/types.h> 36#include <linux/types.h>
37#include <linux/string.h> 37#include <linux/parser.h>
38#include <linux/kernel.h> 38#include <linux/fs.h>
39#include <linux/slab.h>
40#include <linux/nfs_idmap.h> 39#include <linux/nfs_idmap.h>
40#include <net/net_namespace.h>
41#include <linux/sunrpc/rpc_pipe_fs.h>
41#include <linux/nfs_fs.h> 42#include <linux/nfs_fs.h>
43#include <linux/nfs_fs_sb.h>
44#include <linux/key.h>
45#include <linux/keyctl.h>
46#include <linux/key-type.h>
47#include <keys/user-type.h>
48#include <linux/module.h>
49
50#include "internal.h"
51#include "netns.h"
52
53#define NFS_UINT_MAXLEN 11
54
55/* Default cache timeout is 10 minutes */
56unsigned int nfs_idmap_cache_timeout = 600;
57static const struct cred *id_resolver_cache;
58static struct key_type key_type_id_resolver_legacy;
59
42 60
43/** 61/**
44 * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields 62 * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
@@ -142,24 +160,7 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
142 return snprintf(buf, buflen, "%u", id); 160 return snprintf(buf, buflen, "%u", id);
143} 161}
144 162
145#ifdef CONFIG_NFS_USE_NEW_IDMAPPER 163static struct key_type key_type_id_resolver = {
146
147#include <linux/cred.h>
148#include <linux/sunrpc/sched.h>
149#include <linux/nfs4.h>
150#include <linux/nfs_fs_sb.h>
151#include <linux/keyctl.h>
152#include <linux/key-type.h>
153#include <linux/rcupdate.h>
154#include <linux/err.h>
155
156#include <keys/user-type.h>
157
158#define NFS_UINT_MAXLEN 11
159
160const struct cred *id_resolver_cache;
161
162struct key_type key_type_id_resolver = {
163 .name = "id_resolver", 164 .name = "id_resolver",
164 .instantiate = user_instantiate, 165 .instantiate = user_instantiate,
165 .match = user_match, 166 .match = user_match,
@@ -169,13 +170,14 @@ struct key_type key_type_id_resolver = {
169 .read = user_read, 170 .read = user_read,
170}; 171};
171 172
172int nfs_idmap_init(void) 173static int nfs_idmap_init_keyring(void)
173{ 174{
174 struct cred *cred; 175 struct cred *cred;
175 struct key *keyring; 176 struct key *keyring;
176 int ret = 0; 177 int ret = 0;
177 178
178 printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name); 179 printk(KERN_NOTICE "NFS: Registering the %s key type\n",
180 key_type_id_resolver.name);
179 181
180 cred = prepare_kernel_cred(NULL); 182 cred = prepare_kernel_cred(NULL);
181 if (!cred) 183 if (!cred)
@@ -211,7 +213,7 @@ failed_put_cred:
211 return ret; 213 return ret;
212} 214}
213 215
214void nfs_idmap_quit(void) 216static void nfs_idmap_quit_keyring(void)
215{ 217{
216 key_revoke(id_resolver_cache->thread_keyring); 218 key_revoke(id_resolver_cache->thread_keyring);
217 unregister_key_type(&key_type_id_resolver); 219 unregister_key_type(&key_type_id_resolver);
@@ -246,8 +248,10 @@ static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen,
246 return desclen; 248 return desclen;
247} 249}
248 250
249static ssize_t nfs_idmap_request_key(const char *name, size_t namelen, 251static ssize_t nfs_idmap_request_key(struct key_type *key_type,
250 const char *type, void *data, size_t data_size) 252 const char *name, size_t namelen,
253 const char *type, void *data,
254 size_t data_size, struct idmap *idmap)
251{ 255{
252 const struct cred *saved_cred; 256 const struct cred *saved_cred;
253 struct key *rkey; 257 struct key *rkey;
@@ -260,8 +264,12 @@ static ssize_t nfs_idmap_request_key(const char *name, size_t namelen,
260 goto out; 264 goto out;
261 265
262 saved_cred = override_creds(id_resolver_cache); 266 saved_cred = override_creds(id_resolver_cache);
263 rkey = request_key(&key_type_id_resolver, desc, ""); 267 if (idmap)
268 rkey = request_key_with_auxdata(key_type, desc, "", 0, idmap);
269 else
270 rkey = request_key(&key_type_id_resolver, desc, "");
264 revert_creds(saved_cred); 271 revert_creds(saved_cred);
272
265 kfree(desc); 273 kfree(desc);
266 if (IS_ERR(rkey)) { 274 if (IS_ERR(rkey)) {
267 ret = PTR_ERR(rkey); 275 ret = PTR_ERR(rkey);
@@ -294,31 +302,46 @@ out:
294 return ret; 302 return ret;
295} 303}
296 304
305static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
306 const char *type, void *data,
307 size_t data_size, struct idmap *idmap)
308{
309 ssize_t ret = nfs_idmap_request_key(&key_type_id_resolver,
310 name, namelen, type, data,
311 data_size, NULL);
312 if (ret < 0) {
313 ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
314 name, namelen, type, data,
315 data_size, idmap);
316 }
317 return ret;
318}
297 319
298/* ID -> Name */ 320/* ID -> Name */
299static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen) 321static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf,
322 size_t buflen, struct idmap *idmap)
300{ 323{
301 char id_str[NFS_UINT_MAXLEN]; 324 char id_str[NFS_UINT_MAXLEN];
302 int id_len; 325 int id_len;
303 ssize_t ret; 326 ssize_t ret;
304 327
305 id_len = snprintf(id_str, sizeof(id_str), "%u", id); 328 id_len = snprintf(id_str, sizeof(id_str), "%u", id);
306 ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen); 329 ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap);
307 if (ret < 0) 330 if (ret < 0)
308 return -EINVAL; 331 return -EINVAL;
309 return ret; 332 return ret;
310} 333}
311 334
312/* Name -> ID */ 335/* Name -> ID */
313static int nfs_idmap_lookup_id(const char *name, size_t namelen, 336static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type,
314 const char *type, __u32 *id) 337 __u32 *id, struct idmap *idmap)
315{ 338{
316 char id_str[NFS_UINT_MAXLEN]; 339 char id_str[NFS_UINT_MAXLEN];
317 long id_long; 340 long id_long;
318 ssize_t data_size; 341 ssize_t data_size;
319 int ret = 0; 342 int ret = 0;
320 343
321 data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN); 344 data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap);
322 if (data_size <= 0) { 345 if (data_size <= 0) {
323 ret = -EINVAL; 346 ret = -EINVAL;
324 } else { 347 } else {
@@ -328,114 +351,103 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen,
328 return ret; 351 return ret;
329} 352}
330 353
331int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) 354/* idmap classic begins here */
332{ 355module_param(nfs_idmap_cache_timeout, int, 0644);
333 if (nfs_map_string_to_numeric(name, namelen, uid))
334 return 0;
335 return nfs_idmap_lookup_id(name, namelen, "uid", uid);
336}
337
338int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
339{
340 if (nfs_map_string_to_numeric(name, namelen, gid))
341 return 0;
342 return nfs_idmap_lookup_id(name, namelen, "gid", gid);
343}
344
345int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
346{
347 int ret = -EINVAL;
348
349 if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
350 ret = nfs_idmap_lookup_name(uid, "user", buf, buflen);
351 if (ret < 0)
352 ret = nfs_map_numeric_to_string(uid, buf, buflen);
353 return ret;
354}
355int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
356{
357 int ret = -EINVAL;
358 356
359 if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) 357struct idmap {
360 ret = nfs_idmap_lookup_name(gid, "group", buf, buflen); 358 struct rpc_pipe *idmap_pipe;
361 if (ret < 0) 359 struct key_construction *idmap_key_cons;
362 ret = nfs_map_numeric_to_string(gid, buf, buflen);
363 return ret;
364}
365
366#else /* CONFIG_NFS_USE_NEW_IDMAPPER not defined */
367
368#include <linux/module.h>
369#include <linux/mutex.h>
370#include <linux/init.h>
371#include <linux/socket.h>
372#include <linux/in.h>
373#include <linux/sched.h>
374#include <linux/sunrpc/clnt.h>
375#include <linux/workqueue.h>
376#include <linux/sunrpc/rpc_pipe_fs.h>
377
378#include <linux/nfs_fs.h>
379
380#include "nfs4_fs.h"
381
382#define IDMAP_HASH_SZ 128
383
384/* Default cache timeout is 10 minutes */
385unsigned int nfs_idmap_cache_timeout = 600 * HZ;
386
387static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
388{
389 char *endp;
390 int num = simple_strtol(val, &endp, 0);
391 int jif = num * HZ;
392 if (endp == val || *endp || num < 0 || jif < num)
393 return -EINVAL;
394 *((int *)kp->arg) = jif;
395 return 0;
396}
397
398module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
399 &nfs_idmap_cache_timeout, 0644);
400
401struct idmap_hashent {
402 unsigned long ih_expires;
403 __u32 ih_id;
404 size_t ih_namelen;
405 char ih_name[IDMAP_NAMESZ];
406}; 360};
407 361
408struct idmap_hashtable { 362enum {
409 __u8 h_type; 363 Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err
410 struct idmap_hashent h_entries[IDMAP_HASH_SZ];
411}; 364};
412 365
413struct idmap { 366static const match_table_t nfs_idmap_tokens = {
414 struct dentry *idmap_dentry; 367 { Opt_find_uid, "uid:%s" },
415 wait_queue_head_t idmap_wq; 368 { Opt_find_gid, "gid:%s" },
416 struct idmap_msg idmap_im; 369 { Opt_find_user, "user:%s" },
417 struct mutex idmap_lock; /* Serializes upcalls */ 370 { Opt_find_group, "group:%s" },
418 struct mutex idmap_im_lock; /* Protects the hashtable */ 371 { Opt_find_err, NULL }
419 struct idmap_hashtable idmap_user_hash;
420 struct idmap_hashtable idmap_group_hash;
421}; 372};
422 373
374static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
423static ssize_t idmap_pipe_downcall(struct file *, const char __user *, 375static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
424 size_t); 376 size_t);
425static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); 377static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
426 378
427static unsigned int fnvhash32(const void *, size_t);
428
429static const struct rpc_pipe_ops idmap_upcall_ops = { 379static const struct rpc_pipe_ops idmap_upcall_ops = {
430 .upcall = rpc_pipe_generic_upcall, 380 .upcall = rpc_pipe_generic_upcall,
431 .downcall = idmap_pipe_downcall, 381 .downcall = idmap_pipe_downcall,
432 .destroy_msg = idmap_pipe_destroy_msg, 382 .destroy_msg = idmap_pipe_destroy_msg,
433}; 383};
434 384
385static struct key_type key_type_id_resolver_legacy = {
386 .name = "id_resolver",
387 .instantiate = user_instantiate,
388 .match = user_match,
389 .revoke = user_revoke,
390 .destroy = user_destroy,
391 .describe = user_describe,
392 .read = user_read,
393 .request_key = nfs_idmap_legacy_upcall,
394};
395
396static void __nfs_idmap_unregister(struct rpc_pipe *pipe)
397{
398 if (pipe->dentry)
399 rpc_unlink(pipe->dentry);
400}
401
402static int __nfs_idmap_register(struct dentry *dir,
403 struct idmap *idmap,
404 struct rpc_pipe *pipe)
405{
406 struct dentry *dentry;
407
408 dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe);
409 if (IS_ERR(dentry))
410 return PTR_ERR(dentry);
411 pipe->dentry = dentry;
412 return 0;
413}
414
415static void nfs_idmap_unregister(struct nfs_client *clp,
416 struct rpc_pipe *pipe)
417{
418 struct net *net = clp->net;
419 struct super_block *pipefs_sb;
420
421 pipefs_sb = rpc_get_sb_net(net);
422 if (pipefs_sb) {
423 __nfs_idmap_unregister(pipe);
424 rpc_put_sb_net(net);
425 }
426}
427
428static int nfs_idmap_register(struct nfs_client *clp,
429 struct idmap *idmap,
430 struct rpc_pipe *pipe)
431{
432 struct net *net = clp->net;
433 struct super_block *pipefs_sb;
434 int err = 0;
435
436 pipefs_sb = rpc_get_sb_net(net);
437 if (pipefs_sb) {
438 if (clp->cl_rpcclient->cl_dentry)
439 err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
440 idmap, pipe);
441 rpc_put_sb_net(net);
442 }
443 return err;
444}
445
435int 446int
436nfs_idmap_new(struct nfs_client *clp) 447nfs_idmap_new(struct nfs_client *clp)
437{ 448{
438 struct idmap *idmap; 449 struct idmap *idmap;
450 struct rpc_pipe *pipe;
439 int error; 451 int error;
440 452
441 BUG_ON(clp->cl_idmap != NULL); 453 BUG_ON(clp->cl_idmap != NULL);
@@ -444,19 +456,19 @@ nfs_idmap_new(struct nfs_client *clp)
444 if (idmap == NULL) 456 if (idmap == NULL)
445 return -ENOMEM; 457 return -ENOMEM;
446 458
447 idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry, 459 pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0);
448 "idmap", idmap, &idmap_upcall_ops, 0); 460 if (IS_ERR(pipe)) {
449 if (IS_ERR(idmap->idmap_dentry)) { 461 error = PTR_ERR(pipe);
450 error = PTR_ERR(idmap->idmap_dentry);
451 kfree(idmap); 462 kfree(idmap);
452 return error; 463 return error;
453 } 464 }
454 465 error = nfs_idmap_register(clp, idmap, pipe);
455 mutex_init(&idmap->idmap_lock); 466 if (error) {
456 mutex_init(&idmap->idmap_im_lock); 467 rpc_destroy_pipe_data(pipe);
457 init_waitqueue_head(&idmap->idmap_wq); 468 kfree(idmap);
458 idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; 469 return error;
459 idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; 470 }
471 idmap->idmap_pipe = pipe;
460 472
461 clp->cl_idmap = idmap; 473 clp->cl_idmap = idmap;
462 return 0; 474 return 0;
@@ -469,211 +481,220 @@ nfs_idmap_delete(struct nfs_client *clp)
469 481
470 if (!idmap) 482 if (!idmap)
471 return; 483 return;
472 rpc_unlink(idmap->idmap_dentry); 484 nfs_idmap_unregister(clp, idmap->idmap_pipe);
485 rpc_destroy_pipe_data(idmap->idmap_pipe);
473 clp->cl_idmap = NULL; 486 clp->cl_idmap = NULL;
474 kfree(idmap); 487 kfree(idmap);
475} 488}
476 489
477/* 490static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event,
478 * Helper routines for manipulating the hashtable 491 struct super_block *sb)
479 */
480static inline struct idmap_hashent *
481idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len)
482{
483 return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ];
484}
485
486static struct idmap_hashent *
487idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
488{ 492{
489 struct idmap_hashent *he = idmap_name_hash(h, name, len); 493 int err = 0;
490 494
491 if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) 495 switch (event) {
492 return NULL; 496 case RPC_PIPEFS_MOUNT:
493 if (time_after(jiffies, he->ih_expires)) 497 BUG_ON(clp->cl_rpcclient->cl_dentry == NULL);
494 return NULL; 498 err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
495 return he; 499 clp->cl_idmap,
500 clp->cl_idmap->idmap_pipe);
501 break;
502 case RPC_PIPEFS_UMOUNT:
503 if (clp->cl_idmap->idmap_pipe) {
504 struct dentry *parent;
505
506 parent = clp->cl_idmap->idmap_pipe->dentry->d_parent;
507 __nfs_idmap_unregister(clp->cl_idmap->idmap_pipe);
508 /*
509 * Note: This is a dirty hack. SUNRPC hook has been
510 * called already but simple_rmdir() call for the
511 * directory returned with error because of idmap pipe
512 * inside. Thus now we have to remove this directory
513 * here.
514 */
515 if (rpc_rmdir(parent))
516 printk(KERN_ERR "NFS: %s: failed to remove "
517 "clnt dir!\n", __func__);
518 }
519 break;
520 default:
521 printk(KERN_ERR "NFS: %s: unknown event: %ld\n", __func__,
522 event);
523 return -ENOTSUPP;
524 }
525 return err;
526}
527
528static struct nfs_client *nfs_get_client_for_event(struct net *net, int event)
529{
530 struct nfs_net *nn = net_generic(net, nfs_net_id);
531 struct dentry *cl_dentry;
532 struct nfs_client *clp;
533
534 spin_lock(&nn->nfs_client_lock);
535 list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
536 if (clp->rpc_ops != &nfs_v4_clientops)
537 continue;
538 cl_dentry = clp->cl_idmap->idmap_pipe->dentry;
539 if (((event == RPC_PIPEFS_MOUNT) && cl_dentry) ||
540 ((event == RPC_PIPEFS_UMOUNT) && !cl_dentry))
541 continue;
542 atomic_inc(&clp->cl_count);
543 spin_unlock(&nn->nfs_client_lock);
544 return clp;
545 }
546 spin_unlock(&nn->nfs_client_lock);
547 return NULL;
496} 548}
497 549
498static inline struct idmap_hashent * 550static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
499idmap_id_hash(struct idmap_hashtable* h, __u32 id) 551 void *ptr)
500{ 552{
501 return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ]; 553 struct super_block *sb = ptr;
502} 554 struct nfs_client *clp;
555 int error = 0;
503 556
504static struct idmap_hashent * 557 while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) {
505idmap_lookup_id(struct idmap_hashtable *h, __u32 id) 558 error = __rpc_pipefs_event(clp, event, sb);
506{ 559 nfs_put_client(clp);
507 struct idmap_hashent *he = idmap_id_hash(h, id); 560 if (error)
508 if (he->ih_id != id || he->ih_namelen == 0) 561 break;
509 return NULL; 562 }
510 if (time_after(jiffies, he->ih_expires)) 563 return error;
511 return NULL;
512 return he;
513} 564}
514 565
515/* 566#define PIPEFS_NFS_PRIO 1
516 * Routines for allocating new entries in the hashtable. 567
517 * For now, we just have 1 entry per bucket, so it's all 568static struct notifier_block nfs_idmap_block = {
518 * pretty trivial. 569 .notifier_call = rpc_pipefs_event,
519 */ 570 .priority = SUNRPC_PIPEFS_NFS_PRIO,
520static inline struct idmap_hashent * 571};
521idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len)
522{
523 return idmap_name_hash(h, name, len);
524}
525 572
526static inline struct idmap_hashent * 573int nfs_idmap_init(void)
527idmap_alloc_id(struct idmap_hashtable *h, __u32 id)
528{ 574{
529 return idmap_id_hash(h, id); 575 int ret;
576 ret = nfs_idmap_init_keyring();
577 if (ret != 0)
578 goto out;
579 ret = rpc_pipefs_notifier_register(&nfs_idmap_block);
580 if (ret != 0)
581 nfs_idmap_quit_keyring();
582out:
583 return ret;
530} 584}
531 585
532static void 586void nfs_idmap_quit(void)
533idmap_update_entry(struct idmap_hashent *he, const char *name,
534 size_t namelen, __u32 id)
535{ 587{
536 he->ih_id = id; 588 rpc_pipefs_notifier_unregister(&nfs_idmap_block);
537 memcpy(he->ih_name, name, namelen); 589 nfs_idmap_quit_keyring();
538 he->ih_name[namelen] = '\0';
539 he->ih_namelen = namelen;
540 he->ih_expires = jiffies + nfs_idmap_cache_timeout;
541} 590}
542 591
543/* 592static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
544 * Name -> ID 593 struct rpc_pipe_msg *msg)
545 */
546static int
547nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
548 const char *name, size_t namelen, __u32 *id)
549{ 594{
550 struct rpc_pipe_msg msg; 595 substring_t substr;
551 struct idmap_msg *im; 596 int token, ret;
552 struct idmap_hashent *he;
553 DECLARE_WAITQUEUE(wq, current);
554 int ret = -EIO;
555
556 im = &idmap->idmap_im;
557
558 /*
559 * String sanity checks
560 * Note that the userland daemon expects NUL terminated strings
561 */
562 for (;;) {
563 if (namelen == 0)
564 return -EINVAL;
565 if (name[namelen-1] != '\0')
566 break;
567 namelen--;
568 }
569 if (namelen >= IDMAP_NAMESZ)
570 return -EINVAL;
571 597
572 mutex_lock(&idmap->idmap_lock); 598 memset(im, 0, sizeof(*im));
573 mutex_lock(&idmap->idmap_im_lock); 599 memset(msg, 0, sizeof(*msg));
574
575 he = idmap_lookup_name(h, name, namelen);
576 if (he != NULL) {
577 *id = he->ih_id;
578 ret = 0;
579 goto out;
580 }
581 600
582 memset(im, 0, sizeof(*im)); 601 im->im_type = IDMAP_TYPE_GROUP;
583 memcpy(im->im_name, name, namelen); 602 token = match_token(desc, nfs_idmap_tokens, &substr);
584 603
585 im->im_type = h->h_type; 604 switch (token) {
586 im->im_conv = IDMAP_CONV_NAMETOID; 605 case Opt_find_uid:
606 im->im_type = IDMAP_TYPE_USER;
607 case Opt_find_gid:
608 im->im_conv = IDMAP_CONV_NAMETOID;
609 ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ);
610 break;
587 611
588 memset(&msg, 0, sizeof(msg)); 612 case Opt_find_user:
589 msg.data = im; 613 im->im_type = IDMAP_TYPE_USER;
590 msg.len = sizeof(*im); 614 case Opt_find_group:
615 im->im_conv = IDMAP_CONV_IDTONAME;
616 ret = match_int(&substr, &im->im_id);
617 break;
591 618
592 add_wait_queue(&idmap->idmap_wq, &wq); 619 default:
593 if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { 620 ret = -EINVAL;
594 remove_wait_queue(&idmap->idmap_wq, &wq);
595 goto out; 621 goto out;
596 } 622 }
597 623
598 set_current_state(TASK_UNINTERRUPTIBLE); 624 msg->data = im;
599 mutex_unlock(&idmap->idmap_im_lock); 625 msg->len = sizeof(struct idmap_msg);
600 schedule();
601 __set_current_state(TASK_RUNNING);
602 remove_wait_queue(&idmap->idmap_wq, &wq);
603 mutex_lock(&idmap->idmap_im_lock);
604 626
605 if (im->im_status & IDMAP_STATUS_SUCCESS) { 627out:
606 *id = im->im_id;
607 ret = 0;
608 }
609
610 out:
611 memset(im, 0, sizeof(*im));
612 mutex_unlock(&idmap->idmap_im_lock);
613 mutex_unlock(&idmap->idmap_lock);
614 return ret; 628 return ret;
615} 629}
616 630
617/* 631static int nfs_idmap_legacy_upcall(struct key_construction *cons,
618 * ID -> Name 632 const char *op,
619 */ 633 void *aux)
620static int
621nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
622 __u32 id, char *name)
623{ 634{
624 struct rpc_pipe_msg msg; 635 struct rpc_pipe_msg *msg;
625 struct idmap_msg *im; 636 struct idmap_msg *im;
626 struct idmap_hashent *he; 637 struct idmap *idmap = (struct idmap *)aux;
627 DECLARE_WAITQUEUE(wq, current); 638 struct key *key = cons->key;
628 int ret = -EIO; 639 int ret;
629 unsigned int len;
630
631 im = &idmap->idmap_im;
632 640
633 mutex_lock(&idmap->idmap_lock); 641 /* msg and im are freed in idmap_pipe_destroy_msg */
634 mutex_lock(&idmap->idmap_im_lock); 642 msg = kmalloc(sizeof(*msg), GFP_KERNEL);
643 if (IS_ERR(msg)) {
644 ret = PTR_ERR(msg);
645 goto out0;
646 }
635 647
636 he = idmap_lookup_id(h, id); 648 im = kmalloc(sizeof(*im), GFP_KERNEL);
637 if (he) { 649 if (IS_ERR(im)) {
638 memcpy(name, he->ih_name, he->ih_namelen); 650 ret = PTR_ERR(im);
639 ret = he->ih_namelen; 651 goto out1;
640 goto out;
641 } 652 }
642 653
643 memset(im, 0, sizeof(*im)); 654 ret = nfs_idmap_prepare_message(key->description, im, msg);
644 im->im_type = h->h_type; 655 if (ret < 0)
645 im->im_conv = IDMAP_CONV_IDTONAME; 656 goto out2;
646 im->im_id = id;
647 657
648 memset(&msg, 0, sizeof(msg)); 658 idmap->idmap_key_cons = cons;
649 msg.data = im;
650 msg.len = sizeof(*im);
651 659
652 add_wait_queue(&idmap->idmap_wq, &wq); 660 ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
661 if (ret < 0)
662 goto out2;
653 663
654 if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { 664 return ret;
655 remove_wait_queue(&idmap->idmap_wq, &wq); 665
656 goto out; 666out2:
657 } 667 kfree(im);
668out1:
669 kfree(msg);
670out0:
671 key_revoke(cons->key);
672 key_revoke(cons->authkey);
673 return ret;
674}
675
676static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data)
677{
678 return key_instantiate_and_link(key, data, strlen(data) + 1,
679 id_resolver_cache->thread_keyring,
680 authkey);
681}
658 682
659 set_current_state(TASK_UNINTERRUPTIBLE); 683static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey)
660 mutex_unlock(&idmap->idmap_im_lock); 684{
661 schedule(); 685 char id_str[NFS_UINT_MAXLEN];
662 __set_current_state(TASK_RUNNING); 686 int ret = -EINVAL;
663 remove_wait_queue(&idmap->idmap_wq, &wq); 687
664 mutex_lock(&idmap->idmap_im_lock); 688 switch (im->im_conv) {
665 689 case IDMAP_CONV_NAMETOID:
666 if (im->im_status & IDMAP_STATUS_SUCCESS) { 690 sprintf(id_str, "%d", im->im_id);
667 if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0) 691 ret = nfs_idmap_instantiate(key, authkey, id_str);
668 goto out; 692 break;
669 memcpy(name, im->im_name, len); 693 case IDMAP_CONV_IDTONAME:
670 ret = len; 694 ret = nfs_idmap_instantiate(key, authkey, im->im_name);
695 break;
671 } 696 }
672 697
673 out:
674 memset(im, 0, sizeof(*im));
675 mutex_unlock(&idmap->idmap_im_lock);
676 mutex_unlock(&idmap->idmap_lock);
677 return ret; 698 return ret;
678} 699}
679 700
@@ -682,115 +703,51 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
682{ 703{
683 struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); 704 struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
684 struct idmap *idmap = (struct idmap *)rpci->private; 705 struct idmap *idmap = (struct idmap *)rpci->private;
685 struct idmap_msg im_in, *im = &idmap->idmap_im; 706 struct key_construction *cons = idmap->idmap_key_cons;
686 struct idmap_hashtable *h; 707 struct idmap_msg im;
687 struct idmap_hashent *he = NULL;
688 size_t namelen_in; 708 size_t namelen_in;
689 int ret; 709 int ret;
690 710
691 if (mlen != sizeof(im_in)) 711 if (mlen != sizeof(im)) {
692 return -ENOSPC; 712 ret = -ENOSPC;
693
694 if (copy_from_user(&im_in, src, mlen) != 0)
695 return -EFAULT;
696
697 mutex_lock(&idmap->idmap_im_lock);
698
699 ret = mlen;
700 im->im_status = im_in.im_status;
701 /* If we got an error, terminate now, and wake up pending upcalls */
702 if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) {
703 wake_up(&idmap->idmap_wq);
704 goto out; 713 goto out;
705 } 714 }
706 715
707 /* Sanity checking of strings */ 716 if (copy_from_user(&im, src, mlen) != 0) {
708 ret = -EINVAL; 717 ret = -EFAULT;
709 namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ);
710 if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ)
711 goto out; 718 goto out;
719 }
712 720
713 switch (im_in.im_type) { 721 if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
714 case IDMAP_TYPE_USER: 722 ret = mlen;
715 h = &idmap->idmap_user_hash; 723 complete_request_key(idmap->idmap_key_cons, -ENOKEY);
716 break; 724 goto out_incomplete;
717 case IDMAP_TYPE_GROUP:
718 h = &idmap->idmap_group_hash;
719 break;
720 default:
721 goto out;
722 } 725 }
723 726
724 switch (im_in.im_conv) { 727 namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
725 case IDMAP_CONV_IDTONAME: 728 if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) {
726 /* Did we match the current upcall? */ 729 ret = -EINVAL;
727 if (im->im_conv == IDMAP_CONV_IDTONAME
728 && im->im_type == im_in.im_type
729 && im->im_id == im_in.im_id) {
730 /* Yes: copy string, including the terminating '\0' */
731 memcpy(im->im_name, im_in.im_name, namelen_in);
732 im->im_name[namelen_in] = '\0';
733 wake_up(&idmap->idmap_wq);
734 }
735 he = idmap_alloc_id(h, im_in.im_id);
736 break;
737 case IDMAP_CONV_NAMETOID:
738 /* Did we match the current upcall? */
739 if (im->im_conv == IDMAP_CONV_NAMETOID
740 && im->im_type == im_in.im_type
741 && strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in
742 && memcmp(im->im_name, im_in.im_name, namelen_in) == 0) {
743 im->im_id = im_in.im_id;
744 wake_up(&idmap->idmap_wq);
745 }
746 he = idmap_alloc_name(h, im_in.im_name, namelen_in);
747 break;
748 default:
749 goto out; 730 goto out;
750 } 731 }
751 732
752 /* If the entry is valid, also copy it to the cache */ 733 ret = nfs_idmap_read_message(&im, cons->key, cons->authkey);
753 if (he != NULL) 734 if (ret >= 0) {
754 idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id); 735 key_set_timeout(cons->key, nfs_idmap_cache_timeout);
755 ret = mlen; 736 ret = mlen;
737 }
738
756out: 739out:
757 mutex_unlock(&idmap->idmap_im_lock); 740 complete_request_key(idmap->idmap_key_cons, ret);
741out_incomplete:
758 return ret; 742 return ret;
759} 743}
760 744
761static void 745static void
762idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) 746idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
763{ 747{
764 struct idmap_msg *im = msg->data; 748 /* Free memory allocated in nfs_idmap_legacy_upcall() */
765 struct idmap *idmap = container_of(im, struct idmap, idmap_im); 749 kfree(msg->data);
766 750 kfree(msg);
767 if (msg->errno >= 0)
768 return;
769 mutex_lock(&idmap->idmap_im_lock);
770 im->im_status = IDMAP_STATUS_LOOKUPFAIL;
771 wake_up(&idmap->idmap_wq);
772 mutex_unlock(&idmap->idmap_im_lock);
773}
774
775/*
776 * Fowler/Noll/Vo hash
777 * http://www.isthe.com/chongo/tech/comp/fnv/
778 */
779
780#define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
781#define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
782
783static unsigned int fnvhash32(const void *buf, size_t buflen)
784{
785 const unsigned char *p, *end = (const unsigned char *)buf + buflen;
786 unsigned int hash = FNV_1_32;
787
788 for (p = buf; p < end; p++) {
789 hash *= FNV_P_32;
790 hash ^= (unsigned int)*p;
791 }
792
793 return hash;
794} 751}
795 752
796int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) 753int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
@@ -799,16 +756,16 @@ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_
799 756
800 if (nfs_map_string_to_numeric(name, namelen, uid)) 757 if (nfs_map_string_to_numeric(name, namelen, uid))
801 return 0; 758 return 0;
802 return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); 759 return nfs_idmap_lookup_id(name, namelen, "uid", uid, idmap);
803} 760}
804 761
805int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) 762int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
806{ 763{
807 struct idmap *idmap = server->nfs_client->cl_idmap; 764 struct idmap *idmap = server->nfs_client->cl_idmap;
808 765
809 if (nfs_map_string_to_numeric(name, namelen, uid)) 766 if (nfs_map_string_to_numeric(name, namelen, gid))
810 return 0; 767 return 0;
811 return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); 768 return nfs_idmap_lookup_id(name, namelen, "gid", gid, idmap);
812} 769}
813 770
814int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) 771int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
@@ -817,21 +774,19 @@ int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, s
817 int ret = -EINVAL; 774 int ret = -EINVAL;
818 775
819 if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) 776 if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
820 ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); 777 ret = nfs_idmap_lookup_name(uid, "user", buf, buflen, idmap);
821 if (ret < 0) 778 if (ret < 0)
822 ret = nfs_map_numeric_to_string(uid, buf, buflen); 779 ret = nfs_map_numeric_to_string(uid, buf, buflen);
823 return ret; 780 return ret;
824} 781}
825int nfs_map_gid_to_group(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) 782int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
826{ 783{
827 struct idmap *idmap = server->nfs_client->cl_idmap; 784 struct idmap *idmap = server->nfs_client->cl_idmap;
828 int ret = -EINVAL; 785 int ret = -EINVAL;
829 786
830 if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) 787 if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
831 ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf); 788 ret = nfs_idmap_lookup_name(gid, "group", buf, buflen, idmap);
832 if (ret < 0) 789 if (ret < 0)
833 ret = nfs_map_numeric_to_string(uid, buf, buflen); 790 ret = nfs_map_numeric_to_string(gid, buf, buflen);
834 return ret; 791 return ret;
835} 792}
836
837#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */