aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStanislav Kinsbursky <skinsbursky@parallels.com>2012-01-10 07:13:19 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-01-31 18:20:27 -0500
commiteee17325f1dfbe004f1475743bab9e3d050d00f5 (patch)
treeca48905e04e88658cff7d1a745a12ac3c04cfd77
parent4929d1d33fdbe8385cdd49ccd23563e9ff247ff8 (diff)
NFS: idmap PipeFS notifier introduced
v2: 1) Added "nfs_idmap_init" and "nfs_idmap_quit" definitions for kernels built without CONFIG_NFS_V4 option set. This patch subscribes NFS clients to RPC pipefs notifications. Idmap notifier is registering on NFS module load. This notifier callback is responsible for creation/destruction of PipeFS idmap pipe dentry for NFS4 clients. Since ipdmap pipe is created in rpc client pipefs directory, we have make sure, that this directory has been created already. IOW RPC client notifier callback has been called already. To achive this, PipeFS notifier priorities has been introduced (RPC clients notifier priority is greater than NFS idmap one). But this approach gives another problem: unlink for RPC client directory will be called before NFS idmap pipe unlink on UMOUNT event and will fail, because directory is not empty. The solution, introduced in this patch, is to try to remove client directory once again after idmap pipe was unlinked. This looks like ugly hack, so probably it should be replaced in some more elegant way. Note that no locking required in notifier callback because PipeFS superblock pointer is passed as an argument from it's creation or destruction routine and thus we can be sure about it's validity. Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/client.c4
-rw-r--r--fs/nfs/idmap.c75
-rw-r--r--fs/nfs/internal.h4
-rw-r--r--include/linux/nfs_idmap.h21
-rw-r--r--include/linux/sunrpc/rpc_pipe_fs.h7
-rw-r--r--net/sunrpc/clnt.c1
-rw-r--r--net/sunrpc/rpc_pipe.c16
7 files changed, 116 insertions, 12 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 64815b725409..ca9a4aa38dff 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -52,8 +52,8 @@
52 52
53#define NFSDBG_FACILITY NFSDBG_CLIENT 53#define NFSDBG_FACILITY NFSDBG_CLIENT
54 54
55static DEFINE_SPINLOCK(nfs_client_lock); 55DEFINE_SPINLOCK(nfs_client_lock);
56static LIST_HEAD(nfs_client_list); 56LIST_HEAD(nfs_client_list);
57static LIST_HEAD(nfs_volume_list); 57static LIST_HEAD(nfs_volume_list);
58static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); 58static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
59#ifdef CONFIG_NFS_V4 59#ifdef CONFIG_NFS_V4
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 769274ed51c4..ff084d258c41 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -377,6 +377,7 @@ int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf,
377#include <linux/nfs_fs.h> 377#include <linux/nfs_fs.h>
378 378
379#include "nfs4_fs.h" 379#include "nfs4_fs.h"
380#include "internal.h"
380 381
381#define IDMAP_HASH_SZ 128 382#define IDMAP_HASH_SZ 128
382 383
@@ -530,6 +531,80 @@ nfs_idmap_delete(struct nfs_client *clp)
530 kfree(idmap); 531 kfree(idmap);
531} 532}
532 533
534static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event,
535 struct super_block *sb)
536{
537 int err = 0;
538
539 switch (event) {
540 case RPC_PIPEFS_MOUNT:
541 BUG_ON(clp->cl_rpcclient->cl_dentry == NULL);
542 err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
543 clp->cl_idmap,
544 clp->cl_idmap->idmap_pipe);
545 break;
546 case RPC_PIPEFS_UMOUNT:
547 if (clp->cl_idmap->idmap_pipe) {
548 struct dentry *parent;
549
550 parent = clp->cl_idmap->idmap_pipe->dentry->d_parent;
551 __nfs_idmap_unregister(clp->cl_idmap->idmap_pipe);
552 /*
553 * Note: This is a dirty hack. SUNRPC hook has been
554 * called already but simple_rmdir() call for the
555 * directory returned with error because of idmap pipe
556 * inside. Thus now we have to remove this directory
557 * here.
558 */
559 if (rpc_rmdir(parent))
560 printk(KERN_ERR "%s: failed to remove clnt dir!\n", __func__);
561 }
562 break;
563 default:
564 printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event);
565 return -ENOTSUPP;
566 }
567 return err;
568}
569
570static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
571 void *ptr)
572{
573 struct super_block *sb = ptr;
574 struct nfs_client *clp;
575 int error = 0;
576
577 spin_lock(&nfs_client_lock);
578 list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
579 if (clp->net != sb->s_fs_info)
580 continue;
581 if (clp->rpc_ops != &nfs_v4_clientops)
582 continue;
583 error = __rpc_pipefs_event(clp, event, sb);
584 if (error)
585 break;
586 }
587 spin_unlock(&nfs_client_lock);
588 return error;
589}
590
591#define PIPEFS_NFS_PRIO 1
592
593static struct notifier_block nfs_idmap_block = {
594 .notifier_call = rpc_pipefs_event,
595 .priority = SUNRPC_PIPEFS_NFS_PRIO,
596};
597
598int nfs_idmap_init(void)
599{
600 return rpc_pipefs_notifier_register(&nfs_idmap_block);
601}
602
603void nfs_idmap_quit(void)
604{
605 rpc_pipefs_notifier_unregister(&nfs_idmap_block);
606}
607
533/* 608/*
534 * Helper routines for manipulating the hashtable 609 * Helper routines for manipulating the hashtable
535 */ 610 */
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index d602188f889f..2b9836fe4434 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -182,6 +182,10 @@ static inline void nfs_fs_proc_exit(void)
182{ 182{
183} 183}
184#endif 184#endif
185#ifdef CONFIG_NFS_V4
186extern spinlock_t nfs_client_lock;
187extern struct list_head nfs_client_list;
188#endif
185 189
186/* nfs4namespace.c */ 190/* nfs4namespace.c */
187#ifdef CONFIG_NFS_V4 191#ifdef CONFIG_NFS_V4
diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h
index 308c18877018..3c9eeb7da646 100644
--- a/include/linux/nfs_idmap.h
+++ b/include/linux/nfs_idmap.h
@@ -69,31 +69,32 @@ struct nfs_server;
69struct nfs_fattr; 69struct nfs_fattr;
70struct nfs4_string; 70struct nfs4_string;
71 71
72#ifdef CONFIG_NFS_USE_NEW_IDMAPPER 72#ifdef CONFIG_NFS_V4
73
74int nfs_idmap_init(void); 73int nfs_idmap_init(void);
75void nfs_idmap_quit(void); 74void nfs_idmap_quit(void);
76 75#else
77static inline int nfs_idmap_new(struct nfs_client *clp) 76static inline int nfs_idmap_init(void)
78{ 77{
79 return 0; 78 return 0;
80} 79}
81 80
82static inline void nfs_idmap_delete(struct nfs_client *clp) 81static inline void nfs_idmap_quit(void)
83{ 82{}
84} 83#endif
85 84
86#else /* CONFIG_NFS_USE_NEW_IDMAPPER not set */ 85#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
87 86
88static inline int nfs_idmap_init(void) 87static inline int nfs_idmap_new(struct nfs_client *clp)
89{ 88{
90 return 0; 89 return 0;
91} 90}
92 91
93static inline void nfs_idmap_quit(void) 92static inline void nfs_idmap_delete(struct nfs_client *clp)
94{ 93{
95} 94}
96 95
96#else /* CONFIG_NFS_USE_NEW_IDMAPPER not set */
97
97int nfs_idmap_new(struct nfs_client *); 98int nfs_idmap_new(struct nfs_client *);
98void nfs_idmap_delete(struct nfs_client *); 99void nfs_idmap_delete(struct nfs_client *);
99 100
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
index 0d1f748f76da..ca32ebd14c18 100644
--- a/include/linux/sunrpc/rpc_pipe_fs.h
+++ b/include/linux/sunrpc/rpc_pipe_fs.h
@@ -49,6 +49,11 @@ RPC_I(struct inode *inode)
49 return container_of(inode, struct rpc_inode, vfs_inode); 49 return container_of(inode, struct rpc_inode, vfs_inode);
50} 50}
51 51
52enum {
53 SUNRPC_PIPEFS_NFS_PRIO,
54 SUNRPC_PIPEFS_RPC_PRIO,
55};
56
52extern int rpc_pipefs_notifier_register(struct notifier_block *); 57extern int rpc_pipefs_notifier_register(struct notifier_block *);
53extern void rpc_pipefs_notifier_unregister(struct notifier_block *); 58extern void rpc_pipefs_notifier_unregister(struct notifier_block *);
54 59
@@ -78,6 +83,8 @@ extern struct dentry *rpc_create_cache_dir(struct dentry *,
78 struct cache_detail *); 83 struct cache_detail *);
79extern void rpc_remove_cache_dir(struct dentry *); 84extern void rpc_remove_cache_dir(struct dentry *);
80 85
86extern int rpc_rmdir(struct dentry *dentry);
87
81struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags); 88struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags);
82void rpc_destroy_pipe_data(struct rpc_pipe *pipe); 89void rpc_destroy_pipe_data(struct rpc_pipe *pipe);
83extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *, 90extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *,
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index ed7c22de9319..4c6848017168 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -222,6 +222,7 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
222 222
223static struct notifier_block rpc_clients_block = { 223static struct notifier_block rpc_clients_block = {
224 .notifier_call = rpc_pipefs_event, 224 .notifier_call = rpc_pipefs_event,
225 .priority = SUNRPC_PIPEFS_RPC_PRIO,
225}; 226};
226 227
227int rpc_clients_notifier_register(void) 228int rpc_clients_notifier_register(void)
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 6b417fcabdbf..bae4e71d8663 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -616,6 +616,22 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
616 return ret; 616 return ret;
617} 617}
618 618
619int rpc_rmdir(struct dentry *dentry)
620{
621 struct dentry *parent;
622 struct inode *dir;
623 int error;
624
625 parent = dget_parent(dentry);
626 dir = parent->d_inode;
627 mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
628 error = __rpc_rmdir(dir, dentry);
629 mutex_unlock(&dir->i_mutex);
630 dput(parent);
631 return error;
632}
633EXPORT_SYMBOL_GPL(rpc_rmdir);
634
619static int __rpc_unlink(struct inode *dir, struct dentry *dentry) 635static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
620{ 636{
621 int ret; 637 int ret;