xref: /openbmc/linux/net/sunrpc/rpc_pipe.c (revision 3396f92f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * net/sunrpc/rpc_pipe.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Userland/kernel interface for rpcauth_gss.
51da177e4SLinus Torvalds  * Code shamelessly plagiarized from fs/nfsd/nfsctl.c
6d51fe1beSRolf Eike Beer  * and fs/sysfs/inode.c
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no>
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds #include <linux/module.h>
121da177e4SLinus Torvalds #include <linux/slab.h>
131da177e4SLinus Torvalds #include <linux/string.h>
141da177e4SLinus Torvalds #include <linux/pagemap.h>
151da177e4SLinus Torvalds #include <linux/mount.h>
161da177e4SLinus Torvalds #include <linux/namei.h>
1750e437d5STrond Myklebust #include <linux/fsnotify.h>
181da177e4SLinus Torvalds #include <linux/kernel.h>
192446ab60STrond Myklebust #include <linux/rcupdate.h>
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds #include <asm/ioctls.h>
221da177e4SLinus Torvalds #include <linux/poll.h>
231da177e4SLinus Torvalds #include <linux/wait.h>
241da177e4SLinus Torvalds #include <linux/seq_file.h>
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
271da177e4SLinus Torvalds #include <linux/workqueue.h>
281da177e4SLinus Torvalds #include <linux/sunrpc/rpc_pipe_fs.h>
298854e82dSTrond Myklebust #include <linux/sunrpc/cache.h>
30021c68deSStanislav Kinsbursky #include <linux/nsproxy.h>
312d00131aSStanislav Kinsbursky #include <linux/notifier.h>
321da177e4SLinus Torvalds 
33021c68deSStanislav Kinsbursky #include "netns.h"
342d00131aSStanislav Kinsbursky #include "sunrpc.h"
351da177e4SLinus Torvalds 
36efc46bf2SStanislav Kinsbursky #define RPCDBG_FACILITY RPCDBG_DEBUG
37efc46bf2SStanislav Kinsbursky 
38efc46bf2SStanislav Kinsbursky #define NET_NAME(net)	((net == &init_net) ? " (init_net)" : "")
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type;
414b9a445eSJeff Layton static const struct rpc_pipe_ops gssd_dummy_pipe_ops;
421da177e4SLinus Torvalds 
43e18b890bSChristoph Lameter static struct kmem_cache *rpc_inode_cachep __read_mostly;
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds #define RPC_UPCALL_TIMEOUT (30*HZ)
461da177e4SLinus Torvalds 
472d00131aSStanislav Kinsbursky static BLOCKING_NOTIFIER_HEAD(rpc_pipefs_notifier_list);
482d00131aSStanislav Kinsbursky 
492d00131aSStanislav Kinsbursky int rpc_pipefs_notifier_register(struct notifier_block *nb)
502d00131aSStanislav Kinsbursky {
512d00131aSStanislav Kinsbursky 	return blocking_notifier_chain_cond_register(&rpc_pipefs_notifier_list, nb);
522d00131aSStanislav Kinsbursky }
532d00131aSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_register);
542d00131aSStanislav Kinsbursky 
552d00131aSStanislav Kinsbursky void rpc_pipefs_notifier_unregister(struct notifier_block *nb)
562d00131aSStanislav Kinsbursky {
572d00131aSStanislav Kinsbursky 	blocking_notifier_chain_unregister(&rpc_pipefs_notifier_list, nb);
582d00131aSStanislav Kinsbursky }
592d00131aSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister);
602d00131aSStanislav Kinsbursky 
61591ad7feSStanislav Kinsbursky static void rpc_purge_list(wait_queue_head_t *waitq, struct list_head *head,
629842ef35STrond Myklebust 		void (*destroy_msg)(struct rpc_pipe_msg *), int err)
63b3eb67a2STrond Myklebust {
64b3eb67a2STrond Myklebust 	struct rpc_pipe_msg *msg;
65b3eb67a2STrond Myklebust 
669842ef35STrond Myklebust 	if (list_empty(head))
679842ef35STrond Myklebust 		return;
689842ef35STrond Myklebust 	do {
69b3eb67a2STrond Myklebust 		msg = list_entry(head->next, struct rpc_pipe_msg, list);
705a67657aSTrond Myklebust 		list_del_init(&msg->list);
71b3eb67a2STrond Myklebust 		msg->errno = err;
72b3eb67a2STrond Myklebust 		destroy_msg(msg);
739842ef35STrond Myklebust 	} while (!list_empty(head));
7492123e06SJeff Layton 
7592123e06SJeff Layton 	if (waitq)
76591ad7feSStanislav Kinsbursky 		wake_up(waitq);
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds static void
8065f27f38SDavid Howells rpc_timeout_upcall_queue(struct work_struct *work)
811da177e4SLinus Torvalds {
829842ef35STrond Myklebust 	LIST_HEAD(free_list);
83ba9e0975SStanislav Kinsbursky 	struct rpc_pipe *pipe =
84ba9e0975SStanislav Kinsbursky 		container_of(work, struct rpc_pipe, queue_timeout.work);
859842ef35STrond Myklebust 	void (*destroy_msg)(struct rpc_pipe_msg *);
86591ad7feSStanislav Kinsbursky 	struct dentry *dentry;
871da177e4SLinus Torvalds 
88ba9e0975SStanislav Kinsbursky 	spin_lock(&pipe->lock);
89ba9e0975SStanislav Kinsbursky 	destroy_msg = pipe->ops->destroy_msg;
90ba9e0975SStanislav Kinsbursky 	if (pipe->nreaders == 0) {
91ba9e0975SStanislav Kinsbursky 		list_splice_init(&pipe->pipe, &free_list);
92ba9e0975SStanislav Kinsbursky 		pipe->pipelen = 0;
939842ef35STrond Myklebust 	}
94591ad7feSStanislav Kinsbursky 	dentry = dget(pipe->dentry);
95ba9e0975SStanislav Kinsbursky 	spin_unlock(&pipe->lock);
9692123e06SJeff Layton 	rpc_purge_list(dentry ? &RPC_I(dentry->d_inode)->waitq : NULL,
97591ad7feSStanislav Kinsbursky 			&free_list, destroy_msg, -ETIMEDOUT);
98591ad7feSStanislav Kinsbursky 	dput(dentry);
999842ef35STrond Myklebust }
1001da177e4SLinus Torvalds 
101c1225158SPeng Tao ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg,
102c1225158SPeng Tao 				char __user *dst, size_t buflen)
103c1225158SPeng Tao {
104c1225158SPeng Tao 	char *data = (char *)msg->data + msg->copied;
105c1225158SPeng Tao 	size_t mlen = min(msg->len - msg->copied, buflen);
106c1225158SPeng Tao 	unsigned long left;
107c1225158SPeng Tao 
108c1225158SPeng Tao 	left = copy_to_user(dst, data, mlen);
109c1225158SPeng Tao 	if (left == mlen) {
110c1225158SPeng Tao 		msg->errno = -EFAULT;
111c1225158SPeng Tao 		return -EFAULT;
112c1225158SPeng Tao 	}
113c1225158SPeng Tao 
114c1225158SPeng Tao 	mlen -= left;
115c1225158SPeng Tao 	msg->copied += mlen;
116c1225158SPeng Tao 	msg->errno = 0;
117c1225158SPeng Tao 	return mlen;
118c1225158SPeng Tao }
119c1225158SPeng Tao EXPORT_SYMBOL_GPL(rpc_pipe_generic_upcall);
120c1225158SPeng Tao 
12193a44a75SJ. Bruce Fields /**
1221a5778aaSBen Hutchings  * rpc_queue_upcall - queue an upcall message to userspace
123bda14606SRandy Dunlap  * @pipe: upcall pipe on which to queue given message
12493a44a75SJ. Bruce Fields  * @msg: message to queue
12593a44a75SJ. Bruce Fields  *
12693a44a75SJ. Bruce Fields  * Call with an @inode created by rpc_mkpipe() to queue an upcall.
12793a44a75SJ. Bruce Fields  * A userspace process may then later read the upcall by performing a
12893a44a75SJ. Bruce Fields  * read on an open file for this inode.  It is up to the caller to
12993a44a75SJ. Bruce Fields  * initialize the fields of @msg (other than @msg->list) appropriately.
13093a44a75SJ. Bruce Fields  */
1311da177e4SLinus Torvalds int
132d706ed1fSStanislav Kinsbursky rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg)
1331da177e4SLinus Torvalds {
1346070fe6fSTrond Myklebust 	int res = -EPIPE;
135591ad7feSStanislav Kinsbursky 	struct dentry *dentry;
1361da177e4SLinus Torvalds 
137d0fe13baSStanislav Kinsbursky 	spin_lock(&pipe->lock);
138d0fe13baSStanislav Kinsbursky 	if (pipe->nreaders) {
139d0fe13baSStanislav Kinsbursky 		list_add_tail(&msg->list, &pipe->pipe);
140d0fe13baSStanislav Kinsbursky 		pipe->pipelen += msg->len;
1416070fe6fSTrond Myklebust 		res = 0;
142d0fe13baSStanislav Kinsbursky 	} else if (pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) {
143d0fe13baSStanislav Kinsbursky 		if (list_empty(&pipe->pipe))
14424c5d9d7STrond Myklebust 			queue_delayed_work(rpciod_workqueue,
145d0fe13baSStanislav Kinsbursky 					&pipe->queue_timeout,
1461da177e4SLinus Torvalds 					RPC_UPCALL_TIMEOUT);
147d0fe13baSStanislav Kinsbursky 		list_add_tail(&msg->list, &pipe->pipe);
148d0fe13baSStanislav Kinsbursky 		pipe->pipelen += msg->len;
1496070fe6fSTrond Myklebust 		res = 0;
1506070fe6fSTrond Myklebust 	}
151591ad7feSStanislav Kinsbursky 	dentry = dget(pipe->dentry);
152d0fe13baSStanislav Kinsbursky 	spin_unlock(&pipe->lock);
153591ad7feSStanislav Kinsbursky 	if (dentry) {
154591ad7feSStanislav Kinsbursky 		wake_up(&RPC_I(dentry->d_inode)->waitq);
155591ad7feSStanislav Kinsbursky 		dput(dentry);
156591ad7feSStanislav Kinsbursky 	}
1571da177e4SLinus Torvalds 	return res;
1581da177e4SLinus Torvalds }
159468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_queue_upcall);
1601da177e4SLinus Torvalds 
1616070fe6fSTrond Myklebust static inline void
1626070fe6fSTrond Myklebust rpc_inode_setowner(struct inode *inode, void *private)
1636070fe6fSTrond Myklebust {
1646070fe6fSTrond Myklebust 	RPC_I(inode)->private = private;
1656070fe6fSTrond Myklebust }
1666070fe6fSTrond Myklebust 
1671da177e4SLinus Torvalds static void
1681da177e4SLinus Torvalds rpc_close_pipes(struct inode *inode)
1691da177e4SLinus Torvalds {
170ba9e0975SStanislav Kinsbursky 	struct rpc_pipe *pipe = RPC_I(inode)->pipe;
171e712804aS\"J. Bruce Fields\ 	int need_release;
172ad6b1340SStanislav Kinsbursky 	LIST_HEAD(free_list);
1731da177e4SLinus Torvalds 
1741b1dcc1bSJes Sorensen 	mutex_lock(&inode->i_mutex);
175ba9e0975SStanislav Kinsbursky 	spin_lock(&pipe->lock);
176ba9e0975SStanislav Kinsbursky 	need_release = pipe->nreaders != 0 || pipe->nwriters != 0;
177ba9e0975SStanislav Kinsbursky 	pipe->nreaders = 0;
178ba9e0975SStanislav Kinsbursky 	list_splice_init(&pipe->in_upcall, &free_list);
179ba9e0975SStanislav Kinsbursky 	list_splice_init(&pipe->pipe, &free_list);
180ba9e0975SStanislav Kinsbursky 	pipe->pipelen = 0;
181ad6b1340SStanislav Kinsbursky 	pipe->dentry = NULL;
182ba9e0975SStanislav Kinsbursky 	spin_unlock(&pipe->lock);
183591ad7feSStanislav Kinsbursky 	rpc_purge_list(&RPC_I(inode)->waitq, &free_list, pipe->ops->destroy_msg, -EPIPE);
184ba9e0975SStanislav Kinsbursky 	pipe->nwriters = 0;
185ad6b1340SStanislav Kinsbursky 	if (need_release && pipe->ops->release_pipe)
186ad6b1340SStanislav Kinsbursky 		pipe->ops->release_pipe(inode);
187ba9e0975SStanislav Kinsbursky 	cancel_delayed_work_sync(&pipe->queue_timeout);
1886070fe6fSTrond Myklebust 	rpc_inode_setowner(inode, NULL);
1892c9030eeSStanislav Kinsbursky 	RPC_I(inode)->pipe = NULL;
1901b1dcc1bSJes Sorensen 	mutex_unlock(&inode->i_mutex);
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds static struct inode *
1941da177e4SLinus Torvalds rpc_alloc_inode(struct super_block *sb)
1951da177e4SLinus Torvalds {
1961da177e4SLinus Torvalds 	struct rpc_inode *rpci;
197e94b1766SChristoph Lameter 	rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL);
1981da177e4SLinus Torvalds 	if (!rpci)
1991da177e4SLinus Torvalds 		return NULL;
2001da177e4SLinus Torvalds 	return &rpci->vfs_inode;
2011da177e4SLinus Torvalds }
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds static void
204fa0d7e3dSNick Piggin rpc_i_callback(struct rcu_head *head)
205fa0d7e3dSNick Piggin {
206fa0d7e3dSNick Piggin 	struct inode *inode = container_of(head, struct inode, i_rcu);
207fa0d7e3dSNick Piggin 	kmem_cache_free(rpc_inode_cachep, RPC_I(inode));
208fa0d7e3dSNick Piggin }
209fa0d7e3dSNick Piggin 
210fa0d7e3dSNick Piggin static void
2111da177e4SLinus Torvalds rpc_destroy_inode(struct inode *inode)
2121da177e4SLinus Torvalds {
213fa0d7e3dSNick Piggin 	call_rcu(&inode->i_rcu, rpc_i_callback);
2141da177e4SLinus Torvalds }
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds static int
2171da177e4SLinus Torvalds rpc_pipe_open(struct inode *inode, struct file *filp)
2181da177e4SLinus Torvalds {
2192c9030eeSStanislav Kinsbursky 	struct rpc_pipe *pipe;
220c3810608S\"J. Bruce Fields\ 	int first_open;
2211da177e4SLinus Torvalds 	int res = -ENXIO;
2221da177e4SLinus Torvalds 
2231b1dcc1bSJes Sorensen 	mutex_lock(&inode->i_mutex);
2242c9030eeSStanislav Kinsbursky 	pipe = RPC_I(inode)->pipe;
2252c9030eeSStanislav Kinsbursky 	if (pipe == NULL)
226c3810608S\"J. Bruce Fields\ 		goto out;
227d0fe13baSStanislav Kinsbursky 	first_open = pipe->nreaders == 0 && pipe->nwriters == 0;
228d0fe13baSStanislav Kinsbursky 	if (first_open && pipe->ops->open_pipe) {
229d0fe13baSStanislav Kinsbursky 		res = pipe->ops->open_pipe(inode);
230c3810608S\"J. Bruce Fields\ 		if (res)
231c3810608S\"J. Bruce Fields\ 			goto out;
232c3810608S\"J. Bruce Fields\ 	}
2331da177e4SLinus Torvalds 	if (filp->f_mode & FMODE_READ)
234d0fe13baSStanislav Kinsbursky 		pipe->nreaders++;
2351da177e4SLinus Torvalds 	if (filp->f_mode & FMODE_WRITE)
236d0fe13baSStanislav Kinsbursky 		pipe->nwriters++;
2371da177e4SLinus Torvalds 	res = 0;
238c3810608S\"J. Bruce Fields\ out:
2391b1dcc1bSJes Sorensen 	mutex_unlock(&inode->i_mutex);
2401da177e4SLinus Torvalds 	return res;
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds static int
2441da177e4SLinus Torvalds rpc_pipe_release(struct inode *inode, struct file *filp)
2451da177e4SLinus Torvalds {
2462c9030eeSStanislav Kinsbursky 	struct rpc_pipe *pipe;
2471da177e4SLinus Torvalds 	struct rpc_pipe_msg *msg;
248e712804aS\"J. Bruce Fields\ 	int last_close;
2491da177e4SLinus Torvalds 
2501b1dcc1bSJes Sorensen 	mutex_lock(&inode->i_mutex);
2512c9030eeSStanislav Kinsbursky 	pipe = RPC_I(inode)->pipe;
2522c9030eeSStanislav Kinsbursky 	if (pipe == NULL)
2531da177e4SLinus Torvalds 		goto out;
254655b5bb4SJoe Perches 	msg = filp->private_data;
2551da177e4SLinus Torvalds 	if (msg != NULL) {
256ba9e0975SStanislav Kinsbursky 		spin_lock(&pipe->lock);
25748e49187STrond Myklebust 		msg->errno = -EAGAIN;
2585a67657aSTrond Myklebust 		list_del_init(&msg->list);
259ba9e0975SStanislav Kinsbursky 		spin_unlock(&pipe->lock);
260ba9e0975SStanislav Kinsbursky 		pipe->ops->destroy_msg(msg);
2611da177e4SLinus Torvalds 	}
2621da177e4SLinus Torvalds 	if (filp->f_mode & FMODE_WRITE)
263ba9e0975SStanislav Kinsbursky 		pipe->nwriters --;
2649842ef35STrond Myklebust 	if (filp->f_mode & FMODE_READ) {
265ba9e0975SStanislav Kinsbursky 		pipe->nreaders --;
266ba9e0975SStanislav Kinsbursky 		if (pipe->nreaders == 0) {
2679842ef35STrond Myklebust 			LIST_HEAD(free_list);
268ba9e0975SStanislav Kinsbursky 			spin_lock(&pipe->lock);
269ba9e0975SStanislav Kinsbursky 			list_splice_init(&pipe->pipe, &free_list);
270ba9e0975SStanislav Kinsbursky 			pipe->pipelen = 0;
271ba9e0975SStanislav Kinsbursky 			spin_unlock(&pipe->lock);
272591ad7feSStanislav Kinsbursky 			rpc_purge_list(&RPC_I(inode)->waitq, &free_list,
273ba9e0975SStanislav Kinsbursky 					pipe->ops->destroy_msg, -EAGAIN);
2749842ef35STrond Myklebust 		}
2759842ef35STrond Myklebust 	}
276ba9e0975SStanislav Kinsbursky 	last_close = pipe->nwriters == 0 && pipe->nreaders == 0;
277ba9e0975SStanislav Kinsbursky 	if (last_close && pipe->ops->release_pipe)
278ba9e0975SStanislav Kinsbursky 		pipe->ops->release_pipe(inode);
2791da177e4SLinus Torvalds out:
2801b1dcc1bSJes Sorensen 	mutex_unlock(&inode->i_mutex);
2811da177e4SLinus Torvalds 	return 0;
2821da177e4SLinus Torvalds }
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds static ssize_t
2851da177e4SLinus Torvalds rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
2861da177e4SLinus Torvalds {
287496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
2882c9030eeSStanislav Kinsbursky 	struct rpc_pipe *pipe;
2891da177e4SLinus Torvalds 	struct rpc_pipe_msg *msg;
2901da177e4SLinus Torvalds 	int res = 0;
2911da177e4SLinus Torvalds 
2921b1dcc1bSJes Sorensen 	mutex_lock(&inode->i_mutex);
2932c9030eeSStanislav Kinsbursky 	pipe = RPC_I(inode)->pipe;
2942c9030eeSStanislav Kinsbursky 	if (pipe == NULL) {
2951da177e4SLinus Torvalds 		res = -EPIPE;
2961da177e4SLinus Torvalds 		goto out_unlock;
2971da177e4SLinus Torvalds 	}
2981da177e4SLinus Torvalds 	msg = filp->private_data;
2991da177e4SLinus Torvalds 	if (msg == NULL) {
300d0fe13baSStanislav Kinsbursky 		spin_lock(&pipe->lock);
301d0fe13baSStanislav Kinsbursky 		if (!list_empty(&pipe->pipe)) {
302d0fe13baSStanislav Kinsbursky 			msg = list_entry(pipe->pipe.next,
3031da177e4SLinus Torvalds 					struct rpc_pipe_msg,
3041da177e4SLinus Torvalds 					list);
305d0fe13baSStanislav Kinsbursky 			list_move(&msg->list, &pipe->in_upcall);
306d0fe13baSStanislav Kinsbursky 			pipe->pipelen -= msg->len;
3071da177e4SLinus Torvalds 			filp->private_data = msg;
3081da177e4SLinus Torvalds 			msg->copied = 0;
3091da177e4SLinus Torvalds 		}
310d0fe13baSStanislav Kinsbursky 		spin_unlock(&pipe->lock);
3111da177e4SLinus Torvalds 		if (msg == NULL)
3121da177e4SLinus Torvalds 			goto out_unlock;
3131da177e4SLinus Torvalds 	}
3141da177e4SLinus Torvalds 	/* NOTE: it is up to the callback to update msg->copied */
315d0fe13baSStanislav Kinsbursky 	res = pipe->ops->upcall(filp, msg, buf, len);
3161da177e4SLinus Torvalds 	if (res < 0 || msg->len == msg->copied) {
3171da177e4SLinus Torvalds 		filp->private_data = NULL;
318d0fe13baSStanislav Kinsbursky 		spin_lock(&pipe->lock);
3195a67657aSTrond Myklebust 		list_del_init(&msg->list);
320d0fe13baSStanislav Kinsbursky 		spin_unlock(&pipe->lock);
321d0fe13baSStanislav Kinsbursky 		pipe->ops->destroy_msg(msg);
3221da177e4SLinus Torvalds 	}
3231da177e4SLinus Torvalds out_unlock:
3241b1dcc1bSJes Sorensen 	mutex_unlock(&inode->i_mutex);
3251da177e4SLinus Torvalds 	return res;
3261da177e4SLinus Torvalds }
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds static ssize_t
3291da177e4SLinus Torvalds rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
3301da177e4SLinus Torvalds {
331496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
3321da177e4SLinus Torvalds 	int res;
3331da177e4SLinus Torvalds 
3341b1dcc1bSJes Sorensen 	mutex_lock(&inode->i_mutex);
3351da177e4SLinus Torvalds 	res = -EPIPE;
3362c9030eeSStanislav Kinsbursky 	if (RPC_I(inode)->pipe != NULL)
3372c9030eeSStanislav Kinsbursky 		res = RPC_I(inode)->pipe->ops->downcall(filp, buf, len);
3381b1dcc1bSJes Sorensen 	mutex_unlock(&inode->i_mutex);
3391da177e4SLinus Torvalds 	return res;
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds static unsigned int
3431da177e4SLinus Torvalds rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait)
3441da177e4SLinus Torvalds {
345496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
346591ad7feSStanislav Kinsbursky 	struct rpc_inode *rpci = RPC_I(inode);
347591ad7feSStanislav Kinsbursky 	unsigned int mask = POLLOUT | POLLWRNORM;
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 	poll_wait(filp, &rpci->waitq, wait);
3501da177e4SLinus Torvalds 
351591ad7feSStanislav Kinsbursky 	mutex_lock(&inode->i_mutex);
352591ad7feSStanislav Kinsbursky 	if (rpci->pipe == NULL)
3531da177e4SLinus Torvalds 		mask |= POLLERR | POLLHUP;
354591ad7feSStanislav Kinsbursky 	else if (filp->private_data || !list_empty(&rpci->pipe->pipe))
3551da177e4SLinus Torvalds 		mask |= POLLIN | POLLRDNORM;
356591ad7feSStanislav Kinsbursky 	mutex_unlock(&inode->i_mutex);
3571da177e4SLinus Torvalds 	return mask;
3581da177e4SLinus Torvalds }
3591da177e4SLinus Torvalds 
360a6f8dbc6SArnd Bergmann static long
361a6f8dbc6SArnd Bergmann rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
3621da177e4SLinus Torvalds {
363496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
3642c9030eeSStanislav Kinsbursky 	struct rpc_pipe *pipe;
3651da177e4SLinus Torvalds 	int len;
3661da177e4SLinus Torvalds 
3671da177e4SLinus Torvalds 	switch (cmd) {
3681da177e4SLinus Torvalds 	case FIONREAD:
3692c9030eeSStanislav Kinsbursky 		mutex_lock(&inode->i_mutex);
3702c9030eeSStanislav Kinsbursky 		pipe = RPC_I(inode)->pipe;
3712c9030eeSStanislav Kinsbursky 		if (pipe == NULL) {
3722c9030eeSStanislav Kinsbursky 			mutex_unlock(&inode->i_mutex);
3731da177e4SLinus Torvalds 			return -EPIPE;
374a6f8dbc6SArnd Bergmann 		}
3752c9030eeSStanislav Kinsbursky 		spin_lock(&pipe->lock);
376d0fe13baSStanislav Kinsbursky 		len = pipe->pipelen;
3771da177e4SLinus Torvalds 		if (filp->private_data) {
3781da177e4SLinus Torvalds 			struct rpc_pipe_msg *msg;
379655b5bb4SJoe Perches 			msg = filp->private_data;
3801da177e4SLinus Torvalds 			len += msg->len - msg->copied;
3811da177e4SLinus Torvalds 		}
382d0fe13baSStanislav Kinsbursky 		spin_unlock(&pipe->lock);
3832c9030eeSStanislav Kinsbursky 		mutex_unlock(&inode->i_mutex);
3841da177e4SLinus Torvalds 		return put_user(len, (int __user *)arg);
3851da177e4SLinus Torvalds 	default:
3861da177e4SLinus Torvalds 		return -EINVAL;
3871da177e4SLinus Torvalds 	}
3881da177e4SLinus Torvalds }
3891da177e4SLinus Torvalds 
390da7071d7SArjan van de Ven static const struct file_operations rpc_pipe_fops = {
3911da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
3921da177e4SLinus Torvalds 	.llseek		= no_llseek,
3931da177e4SLinus Torvalds 	.read		= rpc_pipe_read,
3941da177e4SLinus Torvalds 	.write		= rpc_pipe_write,
3951da177e4SLinus Torvalds 	.poll		= rpc_pipe_poll,
396674b604cSFrederic Weisbecker 	.unlocked_ioctl	= rpc_pipe_ioctl,
3971da177e4SLinus Torvalds 	.open		= rpc_pipe_open,
3981da177e4SLinus Torvalds 	.release	= rpc_pipe_release,
3991da177e4SLinus Torvalds };
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds static int
4021da177e4SLinus Torvalds rpc_show_info(struct seq_file *m, void *v)
4031da177e4SLinus Torvalds {
4041da177e4SLinus Torvalds 	struct rpc_clnt *clnt = m->private;
4051da177e4SLinus Torvalds 
4062446ab60STrond Myklebust 	rcu_read_lock();
4074e0038b6STrond Myklebust 	seq_printf(m, "RPC server: %s\n",
4084e0038b6STrond Myklebust 			rcu_dereference(clnt->cl_xprt)->servername);
40955909f21STrond Myklebust 	seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_program->name,
4101da177e4SLinus Torvalds 			clnt->cl_prog, clnt->cl_vers);
411e7f78657SChuck Lever 	seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
412e7f78657SChuck Lever 	seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
413bf19aaceSJ. Bruce Fields 	seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT));
4142446ab60STrond Myklebust 	rcu_read_unlock();
4151da177e4SLinus Torvalds 	return 0;
4161da177e4SLinus Torvalds }
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds static int
4191da177e4SLinus Torvalds rpc_info_open(struct inode *inode, struct file *file)
4201da177e4SLinus Torvalds {
421006abe88STrond Myklebust 	struct rpc_clnt *clnt = NULL;
4221da177e4SLinus Torvalds 	int ret = single_open(file, rpc_show_info, NULL);
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 	if (!ret) {
4251da177e4SLinus Torvalds 		struct seq_file *m = file->private_data;
426006abe88STrond Myklebust 
427006abe88STrond Myklebust 		spin_lock(&file->f_path.dentry->d_lock);
428006abe88STrond Myklebust 		if (!d_unhashed(file->f_path.dentry))
4291da177e4SLinus Torvalds 			clnt = RPC_I(inode)->private;
430006abe88STrond Myklebust 		if (clnt != NULL && atomic_inc_not_zero(&clnt->cl_count)) {
431006abe88STrond Myklebust 			spin_unlock(&file->f_path.dentry->d_lock);
4321da177e4SLinus Torvalds 			m->private = clnt;
4331da177e4SLinus Torvalds 		} else {
434006abe88STrond Myklebust 			spin_unlock(&file->f_path.dentry->d_lock);
4351da177e4SLinus Torvalds 			single_release(inode, file);
4361da177e4SLinus Torvalds 			ret = -EINVAL;
4371da177e4SLinus Torvalds 		}
4381da177e4SLinus Torvalds 	}
4391da177e4SLinus Torvalds 	return ret;
4401da177e4SLinus Torvalds }
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds static int
4431da177e4SLinus Torvalds rpc_info_release(struct inode *inode, struct file *file)
4441da177e4SLinus Torvalds {
4451da177e4SLinus Torvalds 	struct seq_file *m = file->private_data;
4461da177e4SLinus Torvalds 	struct rpc_clnt *clnt = (struct rpc_clnt *)m->private;
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 	if (clnt)
4491da177e4SLinus Torvalds 		rpc_release_client(clnt);
4501da177e4SLinus Torvalds 	return single_release(inode, file);
4511da177e4SLinus Torvalds }
4521da177e4SLinus Torvalds 
453da7071d7SArjan van de Ven static const struct file_operations rpc_info_operations = {
4541da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
4551da177e4SLinus Torvalds 	.open		= rpc_info_open,
4561da177e4SLinus Torvalds 	.read		= seq_read,
4571da177e4SLinus Torvalds 	.llseek		= seq_lseek,
4581da177e4SLinus Torvalds 	.release	= rpc_info_release,
4591da177e4SLinus Torvalds };
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds /*
4631da177e4SLinus Torvalds  * Description of fs contents.
4641da177e4SLinus Torvalds  */
4651da177e4SLinus Torvalds struct rpc_filelist {
466ac6feceeSTrond Myklebust 	const char *name;
46799ac48f5SArjan van de Ven 	const struct file_operations *i_fop;
4687364af6aSTrond Myklebust 	umode_t mode;
4691da177e4SLinus Torvalds };
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds static struct inode *
4727364af6aSTrond Myklebust rpc_get_inode(struct super_block *sb, umode_t mode)
4731da177e4SLinus Torvalds {
4741da177e4SLinus Torvalds 	struct inode *inode = new_inode(sb);
4751da177e4SLinus Torvalds 	if (!inode)
4761da177e4SLinus Torvalds 		return NULL;
47785fe4025SChristoph Hellwig 	inode->i_ino = get_next_ino();
4781da177e4SLinus Torvalds 	inode->i_mode = mode;
4791da177e4SLinus Torvalds 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
4801da177e4SLinus Torvalds 	switch (mode & S_IFMT) {
4811da177e4SLinus Torvalds 	case S_IFDIR:
4821da177e4SLinus Torvalds 		inode->i_fop = &simple_dir_operations;
483275448ebSJeff Layton 		inode->i_op = &simple_dir_inode_operations;
484d8c76e6fSDave Hansen 		inc_nlink(inode);
4851da177e4SLinus Torvalds 	default:
4861da177e4SLinus Torvalds 		break;
4871da177e4SLinus Torvalds 	}
4881da177e4SLinus Torvalds 	return inode;
4891da177e4SLinus Torvalds }
4901da177e4SLinus Torvalds 
4917589806eSTrond Myklebust static int __rpc_create_common(struct inode *dir, struct dentry *dentry,
4927589806eSTrond Myklebust 			       umode_t mode,
4937589806eSTrond Myklebust 			       const struct file_operations *i_fop,
4947589806eSTrond Myklebust 			       void *private)
4957589806eSTrond Myklebust {
4967589806eSTrond Myklebust 	struct inode *inode;
4977589806eSTrond Myklebust 
498beb0f0a9STrond Myklebust 	d_drop(dentry);
4997589806eSTrond Myklebust 	inode = rpc_get_inode(dir->i_sb, mode);
5007589806eSTrond Myklebust 	if (!inode)
5017589806eSTrond Myklebust 		goto out_err;
5027589806eSTrond Myklebust 	inode->i_ino = iunique(dir->i_sb, 100);
5037589806eSTrond Myklebust 	if (i_fop)
5047589806eSTrond Myklebust 		inode->i_fop = i_fop;
5057589806eSTrond Myklebust 	if (private)
5067589806eSTrond Myklebust 		rpc_inode_setowner(inode, private);
5077589806eSTrond Myklebust 	d_add(dentry, inode);
5087589806eSTrond Myklebust 	return 0;
5097589806eSTrond Myklebust out_err:
5101e903edaSAl Viro 	printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %pd\n",
5111e903edaSAl Viro 			__FILE__, __func__, dentry);
5127589806eSTrond Myklebust 	dput(dentry);
5137589806eSTrond Myklebust 	return -ENOMEM;
5147589806eSTrond Myklebust }
5157589806eSTrond Myklebust 
516ac6feceeSTrond Myklebust static int __rpc_create(struct inode *dir, struct dentry *dentry,
517ac6feceeSTrond Myklebust 			umode_t mode,
518ac6feceeSTrond Myklebust 			const struct file_operations *i_fop,
519ac6feceeSTrond Myklebust 			void *private)
520ac6feceeSTrond Myklebust {
521ac6feceeSTrond Myklebust 	int err;
522ac6feceeSTrond Myklebust 
523ac6feceeSTrond Myklebust 	err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private);
524ac6feceeSTrond Myklebust 	if (err)
525ac6feceeSTrond Myklebust 		return err;
526ac6feceeSTrond Myklebust 	fsnotify_create(dir, dentry);
527ac6feceeSTrond Myklebust 	return 0;
528ac6feceeSTrond Myklebust }
529ac6feceeSTrond Myklebust 
5307589806eSTrond Myklebust static int __rpc_mkdir(struct inode *dir, struct dentry *dentry,
5317589806eSTrond Myklebust 		       umode_t mode,
5327589806eSTrond Myklebust 		       const struct file_operations *i_fop,
5337589806eSTrond Myklebust 		       void *private)
5347589806eSTrond Myklebust {
5357589806eSTrond Myklebust 	int err;
5367589806eSTrond Myklebust 
5377589806eSTrond Myklebust 	err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private);
5387589806eSTrond Myklebust 	if (err)
5397589806eSTrond Myklebust 		return err;
5407589806eSTrond Myklebust 	inc_nlink(dir);
5417589806eSTrond Myklebust 	fsnotify_mkdir(dir, dentry);
5427589806eSTrond Myklebust 	return 0;
5437589806eSTrond Myklebust }
5447589806eSTrond Myklebust 
545ba9e0975SStanislav Kinsbursky static void
546ba9e0975SStanislav Kinsbursky init_pipe(struct rpc_pipe *pipe)
547ba9e0975SStanislav Kinsbursky {
548ba9e0975SStanislav Kinsbursky 	pipe->nreaders = 0;
549ba9e0975SStanislav Kinsbursky 	pipe->nwriters = 0;
550ba9e0975SStanislav Kinsbursky 	INIT_LIST_HEAD(&pipe->in_upcall);
551ba9e0975SStanislav Kinsbursky 	INIT_LIST_HEAD(&pipe->in_downcall);
552ba9e0975SStanislav Kinsbursky 	INIT_LIST_HEAD(&pipe->pipe);
553ba9e0975SStanislav Kinsbursky 	pipe->pipelen = 0;
554ba9e0975SStanislav Kinsbursky 	INIT_DELAYED_WORK(&pipe->queue_timeout,
555ba9e0975SStanislav Kinsbursky 			    rpc_timeout_upcall_queue);
556ba9e0975SStanislav Kinsbursky 	pipe->ops = NULL;
557ba9e0975SStanislav Kinsbursky 	spin_lock_init(&pipe->lock);
558c239d83bSStanislav Kinsbursky 	pipe->dentry = NULL;
559ba9e0975SStanislav Kinsbursky }
560ba9e0975SStanislav Kinsbursky 
561c239d83bSStanislav Kinsbursky void rpc_destroy_pipe_data(struct rpc_pipe *pipe)
562c239d83bSStanislav Kinsbursky {
563c239d83bSStanislav Kinsbursky 	kfree(pipe);
564c239d83bSStanislav Kinsbursky }
565c239d83bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_destroy_pipe_data);
566c239d83bSStanislav Kinsbursky 
567c239d83bSStanislav Kinsbursky struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags)
5687589806eSTrond Myklebust {
569ba9e0975SStanislav Kinsbursky 	struct rpc_pipe *pipe;
5707589806eSTrond Myklebust 
571ba9e0975SStanislav Kinsbursky 	pipe = kzalloc(sizeof(struct rpc_pipe), GFP_KERNEL);
572ba9e0975SStanislav Kinsbursky 	if (!pipe)
573c239d83bSStanislav Kinsbursky 		return ERR_PTR(-ENOMEM);
574ba9e0975SStanislav Kinsbursky 	init_pipe(pipe);
575c239d83bSStanislav Kinsbursky 	pipe->ops = ops;
576c239d83bSStanislav Kinsbursky 	pipe->flags = flags;
577c239d83bSStanislav Kinsbursky 	return pipe;
578ba9e0975SStanislav Kinsbursky }
579c239d83bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_mkpipe_data);
580c239d83bSStanislav Kinsbursky 
581c239d83bSStanislav Kinsbursky static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
5827589806eSTrond Myklebust 			       umode_t mode,
5837589806eSTrond Myklebust 			       const struct file_operations *i_fop,
5847589806eSTrond Myklebust 			       void *private,
585c239d83bSStanislav Kinsbursky 			       struct rpc_pipe *pipe)
5867589806eSTrond Myklebust {
5877589806eSTrond Myklebust 	struct rpc_inode *rpci;
5887589806eSTrond Myklebust 	int err;
5897589806eSTrond Myklebust 
5907589806eSTrond Myklebust 	err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private);
5917589806eSTrond Myklebust 	if (err)
5927589806eSTrond Myklebust 		return err;
5937589806eSTrond Myklebust 	rpci = RPC_I(dentry->d_inode);
5947589806eSTrond Myklebust 	rpci->private = private;
595ba9e0975SStanislav Kinsbursky 	rpci->pipe = pipe;
5967589806eSTrond Myklebust 	fsnotify_create(dir, dentry);
5977589806eSTrond Myklebust 	return 0;
5987589806eSTrond Myklebust }
5997589806eSTrond Myklebust 
600ac6feceeSTrond Myklebust static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
601ac6feceeSTrond Myklebust {
602ac6feceeSTrond Myklebust 	int ret;
603ac6feceeSTrond Myklebust 
604ac6feceeSTrond Myklebust 	dget(dentry);
605ac6feceeSTrond Myklebust 	ret = simple_rmdir(dir, dentry);
606ac6feceeSTrond Myklebust 	d_delete(dentry);
607ac6feceeSTrond Myklebust 	dput(dentry);
608ac6feceeSTrond Myklebust 	return ret;
609ac6feceeSTrond Myklebust }
610ac6feceeSTrond Myklebust 
611eee17325SStanislav Kinsbursky int rpc_rmdir(struct dentry *dentry)
612eee17325SStanislav Kinsbursky {
613eee17325SStanislav Kinsbursky 	struct dentry *parent;
614eee17325SStanislav Kinsbursky 	struct inode *dir;
615eee17325SStanislav Kinsbursky 	int error;
616eee17325SStanislav Kinsbursky 
617eee17325SStanislav Kinsbursky 	parent = dget_parent(dentry);
618eee17325SStanislav Kinsbursky 	dir = parent->d_inode;
619eee17325SStanislav Kinsbursky 	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
620eee17325SStanislav Kinsbursky 	error = __rpc_rmdir(dir, dentry);
621eee17325SStanislav Kinsbursky 	mutex_unlock(&dir->i_mutex);
622eee17325SStanislav Kinsbursky 	dput(parent);
623eee17325SStanislav Kinsbursky 	return error;
624eee17325SStanislav Kinsbursky }
625eee17325SStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_rmdir);
626eee17325SStanislav Kinsbursky 
627810d90bcSTrond Myklebust static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
628810d90bcSTrond Myklebust {
629810d90bcSTrond Myklebust 	int ret;
630810d90bcSTrond Myklebust 
631810d90bcSTrond Myklebust 	dget(dentry);
632810d90bcSTrond Myklebust 	ret = simple_unlink(dir, dentry);
633810d90bcSTrond Myklebust 	d_delete(dentry);
634810d90bcSTrond Myklebust 	dput(dentry);
635810d90bcSTrond Myklebust 	return ret;
636810d90bcSTrond Myklebust }
637810d90bcSTrond Myklebust 
638810d90bcSTrond Myklebust static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry)
639810d90bcSTrond Myklebust {
640810d90bcSTrond Myklebust 	struct inode *inode = dentry->d_inode;
641810d90bcSTrond Myklebust 
642810d90bcSTrond Myklebust 	rpc_close_pipes(inode);
643810d90bcSTrond Myklebust 	return __rpc_unlink(dir, dentry);
644810d90bcSTrond Myklebust }
645810d90bcSTrond Myklebust 
646cfeaa4a3STrond Myklebust static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
647d3db90b0SAl Viro 					  const char *name)
648cfeaa4a3STrond Myklebust {
649d3db90b0SAl Viro 	struct qstr q = QSTR_INIT(name, strlen(name));
650d3db90b0SAl Viro 	struct dentry *dentry = d_hash_and_lookup(parent, &q);
6515bff0386SStanislav Kinsbursky 	if (!dentry) {
652d3db90b0SAl Viro 		dentry = d_alloc(parent, &q);
6535bff0386SStanislav Kinsbursky 		if (!dentry)
6545bff0386SStanislav Kinsbursky 			return ERR_PTR(-ENOMEM);
6555bff0386SStanislav Kinsbursky 	}
65676fa6665SJeff Layton 	if (dentry->d_inode == NULL)
657f1f0abe1SDan Carpenter 		return dentry;
658cfeaa4a3STrond Myklebust 	dput(dentry);
659cfeaa4a3STrond Myklebust 	return ERR_PTR(-EEXIST);
660cfeaa4a3STrond Myklebust }
661cfeaa4a3STrond Myklebust 
6621da177e4SLinus Torvalds /*
6631da177e4SLinus Torvalds  * FIXME: This probably has races.
6641da177e4SLinus Torvalds  */
665ac6feceeSTrond Myklebust static void __rpc_depopulate(struct dentry *parent,
666ac6feceeSTrond Myklebust 			     const struct rpc_filelist *files,
667ac6feceeSTrond Myklebust 			     int start, int eof)
6681da177e4SLinus Torvalds {
6691da177e4SLinus Torvalds 	struct inode *dir = parent->d_inode;
670ac6feceeSTrond Myklebust 	struct dentry *dentry;
671ac6feceeSTrond Myklebust 	struct qstr name;
672ac6feceeSTrond Myklebust 	int i;
673ac6feceeSTrond Myklebust 
674ac6feceeSTrond Myklebust 	for (i = start; i < eof; i++) {
675ac6feceeSTrond Myklebust 		name.name = files[i].name;
676ac6feceeSTrond Myklebust 		name.len = strlen(files[i].name);
677d3db90b0SAl Viro 		dentry = d_hash_and_lookup(parent, &name);
678ac6feceeSTrond Myklebust 
679ac6feceeSTrond Myklebust 		if (dentry == NULL)
680ac6feceeSTrond Myklebust 			continue;
681ac6feceeSTrond Myklebust 		if (dentry->d_inode == NULL)
682ac6feceeSTrond Myklebust 			goto next;
683ac6feceeSTrond Myklebust 		switch (dentry->d_inode->i_mode & S_IFMT) {
684ac6feceeSTrond Myklebust 			default:
685ac6feceeSTrond Myklebust 				BUG();
686ac6feceeSTrond Myklebust 			case S_IFREG:
687ac6feceeSTrond Myklebust 				__rpc_unlink(dir, dentry);
688ac6feceeSTrond Myklebust 				break;
689ac6feceeSTrond Myklebust 			case S_IFDIR:
690ac6feceeSTrond Myklebust 				__rpc_rmdir(dir, dentry);
691ac6feceeSTrond Myklebust 		}
692ac6feceeSTrond Myklebust next:
693ac6feceeSTrond Myklebust 		dput(dentry);
694ac6feceeSTrond Myklebust 	}
695ac6feceeSTrond Myklebust }
696ac6feceeSTrond Myklebust 
697ac6feceeSTrond Myklebust static void rpc_depopulate(struct dentry *parent,
698ac6feceeSTrond Myklebust 			   const struct rpc_filelist *files,
699ac6feceeSTrond Myklebust 			   int start, int eof)
700ac6feceeSTrond Myklebust {
701ac6feceeSTrond Myklebust 	struct inode *dir = parent->d_inode;
7021da177e4SLinus Torvalds 
703c6573c29SArjan van de Ven 	mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
704ac6feceeSTrond Myklebust 	__rpc_depopulate(parent, files, start, eof);
7051b1dcc1bSJes Sorensen 	mutex_unlock(&dir->i_mutex);
7061da177e4SLinus Torvalds }
7071da177e4SLinus Torvalds 
708ac6feceeSTrond Myklebust static int rpc_populate(struct dentry *parent,
709ac6feceeSTrond Myklebust 			const struct rpc_filelist *files,
710ac6feceeSTrond Myklebust 			int start, int eof,
711ac6feceeSTrond Myklebust 			void *private)
7121da177e4SLinus Torvalds {
713ac6feceeSTrond Myklebust 	struct inode *dir = parent->d_inode;
7141da177e4SLinus Torvalds 	struct dentry *dentry;
715ac6feceeSTrond Myklebust 	int i, err;
7161da177e4SLinus Torvalds 
7171b1dcc1bSJes Sorensen 	mutex_lock(&dir->i_mutex);
7181da177e4SLinus Torvalds 	for (i = start; i < eof; i++) {
719d3db90b0SAl Viro 		dentry = __rpc_lookup_create_exclusive(parent, files[i].name);
720ac6feceeSTrond Myklebust 		err = PTR_ERR(dentry);
721ac6feceeSTrond Myklebust 		if (IS_ERR(dentry))
7221da177e4SLinus Torvalds 			goto out_bad;
723ac6feceeSTrond Myklebust 		switch (files[i].mode & S_IFMT) {
724ac6feceeSTrond Myklebust 			default:
725ac6feceeSTrond Myklebust 				BUG();
726ac6feceeSTrond Myklebust 			case S_IFREG:
727ac6feceeSTrond Myklebust 				err = __rpc_create(dir, dentry,
728ac6feceeSTrond Myklebust 						files[i].mode,
729ac6feceeSTrond Myklebust 						files[i].i_fop,
730ac6feceeSTrond Myklebust 						private);
731ac6feceeSTrond Myklebust 				break;
732ac6feceeSTrond Myklebust 			case S_IFDIR:
733ac6feceeSTrond Myklebust 				err = __rpc_mkdir(dir, dentry,
734ac6feceeSTrond Myklebust 						files[i].mode,
735ac6feceeSTrond Myklebust 						NULL,
736ac6feceeSTrond Myklebust 						private);
7371da177e4SLinus Torvalds 		}
738ac6feceeSTrond Myklebust 		if (err != 0)
739ac6feceeSTrond Myklebust 			goto out_bad;
7401da177e4SLinus Torvalds 	}
7411b1dcc1bSJes Sorensen 	mutex_unlock(&dir->i_mutex);
7421da177e4SLinus Torvalds 	return 0;
7431da177e4SLinus Torvalds out_bad:
744ac6feceeSTrond Myklebust 	__rpc_depopulate(parent, files, start, eof);
7451b1dcc1bSJes Sorensen 	mutex_unlock(&dir->i_mutex);
7461e903edaSAl Viro 	printk(KERN_WARNING "%s: %s failed to populate directory %pd\n",
7471e903edaSAl Viro 			__FILE__, __func__, parent);
748ac6feceeSTrond Myklebust 	return err;
749f134585aSTrond Myklebust }
750f134585aSTrond Myklebust 
751e57aed77STrond Myklebust static struct dentry *rpc_mkdir_populate(struct dentry *parent,
752a95e691fSAl Viro 		const char *name, umode_t mode, void *private,
753e57aed77STrond Myklebust 		int (*populate)(struct dentry *, void *), void *args_populate)
754f134585aSTrond Myklebust {
755f134585aSTrond Myklebust 	struct dentry *dentry;
7567d59d1e8STrond Myklebust 	struct inode *dir = parent->d_inode;
757f134585aSTrond Myklebust 	int error;
758f134585aSTrond Myklebust 
7597d59d1e8STrond Myklebust 	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
7607d59d1e8STrond Myklebust 	dentry = __rpc_lookup_create_exclusive(parent, name);
761f134585aSTrond Myklebust 	if (IS_ERR(dentry))
7627d59d1e8STrond Myklebust 		goto out;
7637d59d1e8STrond Myklebust 	error = __rpc_mkdir(dir, dentry, mode, NULL, private);
7647589806eSTrond Myklebust 	if (error != 0)
7657589806eSTrond Myklebust 		goto out_err;
766e57aed77STrond Myklebust 	if (populate != NULL) {
767e57aed77STrond Myklebust 		error = populate(dentry, args_populate);
768f134585aSTrond Myklebust 		if (error)
769ac6feceeSTrond Myklebust 			goto err_rmdir;
770e57aed77STrond Myklebust 	}
771f134585aSTrond Myklebust out:
7721b1dcc1bSJes Sorensen 	mutex_unlock(&dir->i_mutex);
7735c3e985aSTrond Myklebust 	return dentry;
774ac6feceeSTrond Myklebust err_rmdir:
775f134585aSTrond Myklebust 	__rpc_rmdir(dir, dentry);
7767589806eSTrond Myklebust out_err:
777f134585aSTrond Myklebust 	dentry = ERR_PTR(error);
778f134585aSTrond Myklebust 	goto out;
779f134585aSTrond Myklebust }
780f134585aSTrond Myklebust 
781e57aed77STrond Myklebust static int rpc_rmdir_depopulate(struct dentry *dentry,
782e57aed77STrond Myklebust 		void (*depopulate)(struct dentry *))
783f134585aSTrond Myklebust {
784dff02cc1STrond Myklebust 	struct dentry *parent;
785f134585aSTrond Myklebust 	struct inode *dir;
786f134585aSTrond Myklebust 	int error;
787f134585aSTrond Myklebust 
788dff02cc1STrond Myklebust 	parent = dget_parent(dentry);
789dff02cc1STrond Myklebust 	dir = parent->d_inode;
790c6573c29SArjan van de Ven 	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
791e57aed77STrond Myklebust 	if (depopulate != NULL)
792e57aed77STrond Myklebust 		depopulate(dentry);
793f134585aSTrond Myklebust 	error = __rpc_rmdir(dir, dentry);
7941b1dcc1bSJes Sorensen 	mutex_unlock(&dir->i_mutex);
795dff02cc1STrond Myklebust 	dput(parent);
796f134585aSTrond Myklebust 	return error;
797f134585aSTrond Myklebust }
7981da177e4SLinus Torvalds 
79993a44a75SJ. Bruce Fields /**
80093a44a75SJ. Bruce Fields  * rpc_mkpipe - make an rpc_pipefs file for kernel<->userspace communication
80193a44a75SJ. Bruce Fields  * @parent: dentry of directory to create new "pipe" in
80293a44a75SJ. Bruce Fields  * @name: name of pipe
80393a44a75SJ. Bruce Fields  * @private: private data to associate with the pipe, for the caller's use
804bda14606SRandy Dunlap  * @pipe: &rpc_pipe containing input parameters
80593a44a75SJ. Bruce Fields  *
80693a44a75SJ. Bruce Fields  * Data is made available for userspace to read by calls to
80793a44a75SJ. Bruce Fields  * rpc_queue_upcall().  The actual reads will result in calls to
80893a44a75SJ. Bruce Fields  * @ops->upcall, which will be called with the file pointer,
80993a44a75SJ. Bruce Fields  * message, and userspace buffer to copy to.
81093a44a75SJ. Bruce Fields  *
81193a44a75SJ. Bruce Fields  * Writes can come at any time, and do not necessarily have to be
81293a44a75SJ. Bruce Fields  * responses to upcalls.  They will result in calls to @msg->downcall.
81393a44a75SJ. Bruce Fields  *
81493a44a75SJ. Bruce Fields  * The @private argument passed here will be available to all these methods
815496ad9aaSAl Viro  * from the file pointer, via RPC_I(file_inode(file))->private.
81693a44a75SJ. Bruce Fields  */
817c239d83bSStanislav Kinsbursky struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name,
818c239d83bSStanislav Kinsbursky 				 void *private, struct rpc_pipe *pipe)
8191da177e4SLinus Torvalds {
8201da177e4SLinus Torvalds 	struct dentry *dentry;
8217589806eSTrond Myklebust 	struct inode *dir = parent->d_inode;
8227364af6aSTrond Myklebust 	umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR;
8237589806eSTrond Myklebust 	int err;
8247364af6aSTrond Myklebust 
825c239d83bSStanislav Kinsbursky 	if (pipe->ops->upcall == NULL)
8267364af6aSTrond Myklebust 		umode &= ~S_IRUGO;
827c239d83bSStanislav Kinsbursky 	if (pipe->ops->downcall == NULL)
8287364af6aSTrond Myklebust 		umode &= ~S_IWUGO;
8291da177e4SLinus Torvalds 
830cfeaa4a3STrond Myklebust 	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
831d3db90b0SAl Viro 	dentry = __rpc_lookup_create_exclusive(parent, name);
8321da177e4SLinus Torvalds 	if (IS_ERR(dentry))
833cfeaa4a3STrond Myklebust 		goto out;
834c239d83bSStanislav Kinsbursky 	err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops,
835c239d83bSStanislav Kinsbursky 				  private, pipe);
8367589806eSTrond Myklebust 	if (err)
8377589806eSTrond Myklebust 		goto out_err;
838f134585aSTrond Myklebust out:
8391b1dcc1bSJes Sorensen 	mutex_unlock(&dir->i_mutex);
8405c3e985aSTrond Myklebust 	return dentry;
8417589806eSTrond Myklebust out_err:
8427589806eSTrond Myklebust 	dentry = ERR_PTR(err);
8431e903edaSAl Viro 	printk(KERN_WARNING "%s: %s() failed to create pipe %pd/%s (errno = %d)\n",
8441e903edaSAl Viro 			__FILE__, __func__, parent, name,
8457589806eSTrond Myklebust 			err);
846f134585aSTrond Myklebust 	goto out;
8471da177e4SLinus Torvalds }
848c239d83bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry);
8491da177e4SLinus Torvalds 
85093a44a75SJ. Bruce Fields /**
85193a44a75SJ. Bruce Fields  * rpc_unlink - remove a pipe
85293a44a75SJ. Bruce Fields  * @dentry: dentry for the pipe, as returned from rpc_mkpipe
85393a44a75SJ. Bruce Fields  *
85493a44a75SJ. Bruce Fields  * After this call, lookups will no longer find the pipe, and any
85593a44a75SJ. Bruce Fields  * attempts to read or write using preexisting opens of the pipe will
85693a44a75SJ. Bruce Fields  * return -EPIPE.
85793a44a75SJ. Bruce Fields  */
858f134585aSTrond Myklebust int
8595d67476fSTrond Myklebust rpc_unlink(struct dentry *dentry)
8601da177e4SLinus Torvalds {
8615d67476fSTrond Myklebust 	struct dentry *parent;
862f134585aSTrond Myklebust 	struct inode *dir;
8635d67476fSTrond Myklebust 	int error = 0;
8641da177e4SLinus Torvalds 
8655d67476fSTrond Myklebust 	parent = dget_parent(dentry);
8665d67476fSTrond Myklebust 	dir = parent->d_inode;
867c6573c29SArjan van de Ven 	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
868810d90bcSTrond Myklebust 	error = __rpc_rmpipe(dir, dentry);
8691b1dcc1bSJes Sorensen 	mutex_unlock(&dir->i_mutex);
8705d67476fSTrond Myklebust 	dput(parent);
871f134585aSTrond Myklebust 	return error;
8721da177e4SLinus Torvalds }
873468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_unlink);
8741da177e4SLinus Torvalds 
8756739ffb7STrond Myklebust /**
8766739ffb7STrond Myklebust  * rpc_init_pipe_dir_head - initialise a struct rpc_pipe_dir_head
8776739ffb7STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
8786739ffb7STrond Myklebust  */
8796739ffb7STrond Myklebust void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh)
8806739ffb7STrond Myklebust {
8816739ffb7STrond Myklebust 	INIT_LIST_HEAD(&pdh->pdh_entries);
8826739ffb7STrond Myklebust 	pdh->pdh_dentry = NULL;
8836739ffb7STrond Myklebust }
8846739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_head);
8856739ffb7STrond Myklebust 
8866739ffb7STrond Myklebust /**
8876739ffb7STrond Myklebust  * rpc_init_pipe_dir_object - initialise a struct rpc_pipe_dir_object
8886739ffb7STrond Myklebust  * @pdo: pointer to struct rpc_pipe_dir_object
8896739ffb7STrond Myklebust  * @pdo_ops: pointer to const struct rpc_pipe_dir_object_ops
8906739ffb7STrond Myklebust  * @pdo_data: pointer to caller-defined data
8916739ffb7STrond Myklebust  */
8926739ffb7STrond Myklebust void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo,
8936739ffb7STrond Myklebust 		const struct rpc_pipe_dir_object_ops *pdo_ops,
8946739ffb7STrond Myklebust 		void *pdo_data)
8956739ffb7STrond Myklebust {
8966739ffb7STrond Myklebust 	INIT_LIST_HEAD(&pdo->pdo_head);
8976739ffb7STrond Myklebust 	pdo->pdo_ops = pdo_ops;
8986739ffb7STrond Myklebust 	pdo->pdo_data = pdo_data;
8996739ffb7STrond Myklebust }
9006739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_object);
9016739ffb7STrond Myklebust 
9026739ffb7STrond Myklebust static int
9036739ffb7STrond Myklebust rpc_add_pipe_dir_object_locked(struct net *net,
9046739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
9056739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
9066739ffb7STrond Myklebust {
9076739ffb7STrond Myklebust 	int ret = 0;
9086739ffb7STrond Myklebust 
9096739ffb7STrond Myklebust 	if (pdh->pdh_dentry)
9106739ffb7STrond Myklebust 		ret = pdo->pdo_ops->create(pdh->pdh_dentry, pdo);
9116739ffb7STrond Myklebust 	if (ret == 0)
9126739ffb7STrond Myklebust 		list_add_tail(&pdo->pdo_head, &pdh->pdh_entries);
9136739ffb7STrond Myklebust 	return ret;
9146739ffb7STrond Myklebust }
9156739ffb7STrond Myklebust 
9166739ffb7STrond Myklebust static void
9176739ffb7STrond Myklebust rpc_remove_pipe_dir_object_locked(struct net *net,
9186739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
9196739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
9206739ffb7STrond Myklebust {
9216739ffb7STrond Myklebust 	if (pdh->pdh_dentry)
9226739ffb7STrond Myklebust 		pdo->pdo_ops->destroy(pdh->pdh_dentry, pdo);
9236739ffb7STrond Myklebust 	list_del_init(&pdo->pdo_head);
9246739ffb7STrond Myklebust }
9256739ffb7STrond Myklebust 
9266739ffb7STrond Myklebust /**
9276739ffb7STrond Myklebust  * rpc_add_pipe_dir_object - associate a rpc_pipe_dir_object to a directory
9286739ffb7STrond Myklebust  * @net: pointer to struct net
9296739ffb7STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
9306739ffb7STrond Myklebust  * @pdo: pointer to struct rpc_pipe_dir_object
9316739ffb7STrond Myklebust  *
9326739ffb7STrond Myklebust  */
9336739ffb7STrond Myklebust int
9346739ffb7STrond Myklebust rpc_add_pipe_dir_object(struct net *net,
9356739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
9366739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
9376739ffb7STrond Myklebust {
9386739ffb7STrond Myklebust 	int ret = 0;
9396739ffb7STrond Myklebust 
9406739ffb7STrond Myklebust 	if (list_empty(&pdo->pdo_head)) {
9416739ffb7STrond Myklebust 		struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
9426739ffb7STrond Myklebust 
9436739ffb7STrond Myklebust 		mutex_lock(&sn->pipefs_sb_lock);
9446739ffb7STrond Myklebust 		ret = rpc_add_pipe_dir_object_locked(net, pdh, pdo);
9456739ffb7STrond Myklebust 		mutex_unlock(&sn->pipefs_sb_lock);
9466739ffb7STrond Myklebust 	}
9476739ffb7STrond Myklebust 	return ret;
9486739ffb7STrond Myklebust }
9496739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_add_pipe_dir_object);
9506739ffb7STrond Myklebust 
9516739ffb7STrond Myklebust /**
9526739ffb7STrond Myklebust  * rpc_remove_pipe_dir_object - remove a rpc_pipe_dir_object from a directory
9536739ffb7STrond Myklebust  * @net: pointer to struct net
9546739ffb7STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
9556739ffb7STrond Myklebust  * @pdo: pointer to struct rpc_pipe_dir_object
9566739ffb7STrond Myklebust  *
9576739ffb7STrond Myklebust  */
9586739ffb7STrond Myklebust void
9596739ffb7STrond Myklebust rpc_remove_pipe_dir_object(struct net *net,
9606739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
9616739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
9626739ffb7STrond Myklebust {
9636739ffb7STrond Myklebust 	if (!list_empty(&pdo->pdo_head)) {
9646739ffb7STrond Myklebust 		struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
9656739ffb7STrond Myklebust 
9666739ffb7STrond Myklebust 		mutex_lock(&sn->pipefs_sb_lock);
9676739ffb7STrond Myklebust 		rpc_remove_pipe_dir_object_locked(net, pdh, pdo);
9686739ffb7STrond Myklebust 		mutex_unlock(&sn->pipefs_sb_lock);
9696739ffb7STrond Myklebust 	}
9706739ffb7STrond Myklebust }
9716739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_remove_pipe_dir_object);
9726739ffb7STrond Myklebust 
973298fc355STrond Myklebust /**
974298fc355STrond Myklebust  * rpc_find_or_alloc_pipe_dir_object
975298fc355STrond Myklebust  * @net: pointer to struct net
976298fc355STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
977298fc355STrond Myklebust  * @match: match struct rpc_pipe_dir_object to data
978298fc355STrond Myklebust  * @alloc: allocate a new struct rpc_pipe_dir_object
979298fc355STrond Myklebust  * @data: user defined data for match() and alloc()
980298fc355STrond Myklebust  *
981298fc355STrond Myklebust  */
982298fc355STrond Myklebust struct rpc_pipe_dir_object *
983298fc355STrond Myklebust rpc_find_or_alloc_pipe_dir_object(struct net *net,
984298fc355STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
985298fc355STrond Myklebust 		int (*match)(struct rpc_pipe_dir_object *, void *),
986298fc355STrond Myklebust 		struct rpc_pipe_dir_object *(*alloc)(void *),
987298fc355STrond Myklebust 		void *data)
988298fc355STrond Myklebust {
989298fc355STrond Myklebust 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
990298fc355STrond Myklebust 	struct rpc_pipe_dir_object *pdo;
991298fc355STrond Myklebust 
992298fc355STrond Myklebust 	mutex_lock(&sn->pipefs_sb_lock);
993298fc355STrond Myklebust 	list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) {
994298fc355STrond Myklebust 		if (!match(pdo, data))
995298fc355STrond Myklebust 			continue;
996298fc355STrond Myklebust 		goto out;
997298fc355STrond Myklebust 	}
998298fc355STrond Myklebust 	pdo = alloc(data);
999298fc355STrond Myklebust 	if (!pdo)
1000298fc355STrond Myklebust 		goto out;
1001298fc355STrond Myklebust 	rpc_add_pipe_dir_object_locked(net, pdh, pdo);
1002298fc355STrond Myklebust out:
1003298fc355STrond Myklebust 	mutex_unlock(&sn->pipefs_sb_lock);
1004298fc355STrond Myklebust 	return pdo;
1005298fc355STrond Myklebust }
1006298fc355STrond Myklebust EXPORT_SYMBOL_GPL(rpc_find_or_alloc_pipe_dir_object);
1007298fc355STrond Myklebust 
10086739ffb7STrond Myklebust static void
10096739ffb7STrond Myklebust rpc_create_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
10106739ffb7STrond Myklebust {
10116739ffb7STrond Myklebust 	struct rpc_pipe_dir_object *pdo;
10126739ffb7STrond Myklebust 	struct dentry *dir = pdh->pdh_dentry;
10136739ffb7STrond Myklebust 
10146739ffb7STrond Myklebust 	list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head)
10156739ffb7STrond Myklebust 		pdo->pdo_ops->create(dir, pdo);
10166739ffb7STrond Myklebust }
10176739ffb7STrond Myklebust 
10186739ffb7STrond Myklebust static void
10196739ffb7STrond Myklebust rpc_destroy_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
10206739ffb7STrond Myklebust {
10216739ffb7STrond Myklebust 	struct rpc_pipe_dir_object *pdo;
10226739ffb7STrond Myklebust 	struct dentry *dir = pdh->pdh_dentry;
10236739ffb7STrond Myklebust 
10246739ffb7STrond Myklebust 	list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head)
10256739ffb7STrond Myklebust 		pdo->pdo_ops->destroy(dir, pdo);
10266739ffb7STrond Myklebust }
10276739ffb7STrond Myklebust 
1028e57aed77STrond Myklebust enum {
1029e57aed77STrond Myklebust 	RPCAUTH_info,
1030e57aed77STrond Myklebust 	RPCAUTH_EOF
1031e57aed77STrond Myklebust };
1032e57aed77STrond Myklebust 
1033e57aed77STrond Myklebust static const struct rpc_filelist authfiles[] = {
1034e57aed77STrond Myklebust 	[RPCAUTH_info] = {
1035e57aed77STrond Myklebust 		.name = "info",
1036e57aed77STrond Myklebust 		.i_fop = &rpc_info_operations,
1037e57aed77STrond Myklebust 		.mode = S_IFREG | S_IRUSR,
1038e57aed77STrond Myklebust 	},
1039e57aed77STrond Myklebust };
1040e57aed77STrond Myklebust 
1041e57aed77STrond Myklebust static int rpc_clntdir_populate(struct dentry *dentry, void *private)
1042e57aed77STrond Myklebust {
1043e57aed77STrond Myklebust 	return rpc_populate(dentry,
1044e57aed77STrond Myklebust 			    authfiles, RPCAUTH_info, RPCAUTH_EOF,
1045e57aed77STrond Myklebust 			    private);
1046e57aed77STrond Myklebust }
1047e57aed77STrond Myklebust 
1048e57aed77STrond Myklebust static void rpc_clntdir_depopulate(struct dentry *dentry)
1049e57aed77STrond Myklebust {
1050e57aed77STrond Myklebust 	rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF);
1051e57aed77STrond Myklebust }
1052e57aed77STrond Myklebust 
10537d59d1e8STrond Myklebust /**
10547d59d1e8STrond Myklebust  * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs
1055a95e691fSAl Viro  * @dentry: the parent of new directory
1056a95e691fSAl Viro  * @name: the name of new directory
10577d59d1e8STrond Myklebust  * @rpc_client: rpc client to associate with this directory
10587d59d1e8STrond Myklebust  *
10597d59d1e8STrond Myklebust  * This creates a directory at the given @path associated with
10607d59d1e8STrond Myklebust  * @rpc_clnt, which will contain a file named "info" with some basic
10617d59d1e8STrond Myklebust  * information about the client, together with any "pipes" that may
10627d59d1e8STrond Myklebust  * later be created using rpc_mkpipe().
10637d59d1e8STrond Myklebust  */
106423ac6581STrond Myklebust struct dentry *rpc_create_client_dir(struct dentry *dentry,
1065a95e691fSAl Viro 				   const char *name,
10667d59d1e8STrond Myklebust 				   struct rpc_clnt *rpc_client)
10677d59d1e8STrond Myklebust {
10686739ffb7STrond Myklebust 	struct dentry *ret;
10696739ffb7STrond Myklebust 
10706739ffb7STrond Myklebust 	ret = rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL,
1071e57aed77STrond Myklebust 			rpc_clntdir_populate, rpc_client);
10726739ffb7STrond Myklebust 	if (!IS_ERR(ret)) {
10736739ffb7STrond Myklebust 		rpc_client->cl_pipedir_objects.pdh_dentry = ret;
10746739ffb7STrond Myklebust 		rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
10756739ffb7STrond Myklebust 	}
10766739ffb7STrond Myklebust 	return ret;
1077e57aed77STrond Myklebust }
1078e57aed77STrond Myklebust 
1079e57aed77STrond Myklebust /**
1080e57aed77STrond Myklebust  * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
10816739ffb7STrond Myklebust  * @rpc_client: rpc_client for the pipe
1082e57aed77STrond Myklebust  */
1083c36dcfe1STrond Myklebust int rpc_remove_client_dir(struct rpc_clnt *rpc_client)
1084e57aed77STrond Myklebust {
1085c36dcfe1STrond Myklebust 	struct dentry *dentry = rpc_client->cl_pipedir_objects.pdh_dentry;
1086c36dcfe1STrond Myklebust 
1087c36dcfe1STrond Myklebust 	if (dentry == NULL)
1088c36dcfe1STrond Myklebust 		return 0;
10896739ffb7STrond Myklebust 	rpc_destroy_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
10906739ffb7STrond Myklebust 	rpc_client->cl_pipedir_objects.pdh_dentry = NULL;
1091e57aed77STrond Myklebust 	return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate);
10927d59d1e8STrond Myklebust }
10937d59d1e8STrond Myklebust 
10948854e82dSTrond Myklebust static const struct rpc_filelist cache_pipefs_files[3] = {
10958854e82dSTrond Myklebust 	[0] = {
10968854e82dSTrond Myklebust 		.name = "channel",
10978854e82dSTrond Myklebust 		.i_fop = &cache_file_operations_pipefs,
109896c61cbdSTrond Myklebust 		.mode = S_IFREG|S_IRUSR|S_IWUSR,
10998854e82dSTrond Myklebust 	},
11008854e82dSTrond Myklebust 	[1] = {
11018854e82dSTrond Myklebust 		.name = "content",
11028854e82dSTrond Myklebust 		.i_fop = &content_file_operations_pipefs,
11038854e82dSTrond Myklebust 		.mode = S_IFREG|S_IRUSR,
11048854e82dSTrond Myklebust 	},
11058854e82dSTrond Myklebust 	[2] = {
11068854e82dSTrond Myklebust 		.name = "flush",
11078854e82dSTrond Myklebust 		.i_fop = &cache_flush_operations_pipefs,
11088854e82dSTrond Myklebust 		.mode = S_IFREG|S_IRUSR|S_IWUSR,
11098854e82dSTrond Myklebust 	},
11108854e82dSTrond Myklebust };
11118854e82dSTrond Myklebust 
11128854e82dSTrond Myklebust static int rpc_cachedir_populate(struct dentry *dentry, void *private)
11138854e82dSTrond Myklebust {
11148854e82dSTrond Myklebust 	return rpc_populate(dentry,
11158854e82dSTrond Myklebust 			    cache_pipefs_files, 0, 3,
11168854e82dSTrond Myklebust 			    private);
11178854e82dSTrond Myklebust }
11188854e82dSTrond Myklebust 
11198854e82dSTrond Myklebust static void rpc_cachedir_depopulate(struct dentry *dentry)
11208854e82dSTrond Myklebust {
11218854e82dSTrond Myklebust 	rpc_depopulate(dentry, cache_pipefs_files, 0, 3);
11228854e82dSTrond Myklebust }
11238854e82dSTrond Myklebust 
1124a95e691fSAl Viro struct dentry *rpc_create_cache_dir(struct dentry *parent, const char *name,
112564f1426fSAl Viro 				    umode_t umode, struct cache_detail *cd)
11268854e82dSTrond Myklebust {
11278854e82dSTrond Myklebust 	return rpc_mkdir_populate(parent, name, umode, NULL,
11288854e82dSTrond Myklebust 			rpc_cachedir_populate, cd);
11298854e82dSTrond Myklebust }
11308854e82dSTrond Myklebust 
11318854e82dSTrond Myklebust void rpc_remove_cache_dir(struct dentry *dentry)
11328854e82dSTrond Myklebust {
11338854e82dSTrond Myklebust 	rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate);
11348854e82dSTrond Myklebust }
11358854e82dSTrond Myklebust 
11361da177e4SLinus Torvalds /*
11371da177e4SLinus Torvalds  * populate the filesystem
11381da177e4SLinus Torvalds  */
1139b87221deSAlexey Dobriyan static const struct super_operations s_ops = {
11401da177e4SLinus Torvalds 	.alloc_inode	= rpc_alloc_inode,
11411da177e4SLinus Torvalds 	.destroy_inode	= rpc_destroy_inode,
11421da177e4SLinus Torvalds 	.statfs		= simple_statfs,
11431da177e4SLinus Torvalds };
11441da177e4SLinus Torvalds 
11451da177e4SLinus Torvalds #define RPCAUTH_GSSMAGIC 0x67596969
11461da177e4SLinus Torvalds 
1147bb156749STrond Myklebust /*
1148bb156749STrond Myklebust  * We have a single directory with 1 node in it.
1149bb156749STrond Myklebust  */
1150bb156749STrond Myklebust enum {
1151bb156749STrond Myklebust 	RPCAUTH_lockd,
1152bb156749STrond Myklebust 	RPCAUTH_mount,
1153bb156749STrond Myklebust 	RPCAUTH_nfs,
1154bb156749STrond Myklebust 	RPCAUTH_portmap,
1155bb156749STrond Myklebust 	RPCAUTH_statd,
1156bb156749STrond Myklebust 	RPCAUTH_nfsd4_cb,
1157e571cbf1STrond Myklebust 	RPCAUTH_cache,
1158b3537c35SJeff Layton 	RPCAUTH_nfsd,
11594b9a445eSJeff Layton 	RPCAUTH_gssd,
1160bb156749STrond Myklebust 	RPCAUTH_RootEOF
1161bb156749STrond Myklebust };
1162bb156749STrond Myklebust 
1163bb156749STrond Myklebust static const struct rpc_filelist files[] = {
1164bb156749STrond Myklebust 	[RPCAUTH_lockd] = {
1165bb156749STrond Myklebust 		.name = "lockd",
1166bb156749STrond Myklebust 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
1167bb156749STrond Myklebust 	},
1168bb156749STrond Myklebust 	[RPCAUTH_mount] = {
1169bb156749STrond Myklebust 		.name = "mount",
1170bb156749STrond Myklebust 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
1171bb156749STrond Myklebust 	},
1172bb156749STrond Myklebust 	[RPCAUTH_nfs] = {
1173bb156749STrond Myklebust 		.name = "nfs",
1174bb156749STrond Myklebust 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
1175bb156749STrond Myklebust 	},
1176bb156749STrond Myklebust 	[RPCAUTH_portmap] = {
1177bb156749STrond Myklebust 		.name = "portmap",
1178bb156749STrond Myklebust 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
1179bb156749STrond Myklebust 	},
1180bb156749STrond Myklebust 	[RPCAUTH_statd] = {
1181bb156749STrond Myklebust 		.name = "statd",
1182bb156749STrond Myklebust 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
1183bb156749STrond Myklebust 	},
1184bb156749STrond Myklebust 	[RPCAUTH_nfsd4_cb] = {
1185bb156749STrond Myklebust 		.name = "nfsd4_cb",
1186bb156749STrond Myklebust 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
1187bb156749STrond Myklebust 	},
1188e571cbf1STrond Myklebust 	[RPCAUTH_cache] = {
1189e571cbf1STrond Myklebust 		.name = "cache",
1190e571cbf1STrond Myklebust 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
1191e571cbf1STrond Myklebust 	},
1192b3537c35SJeff Layton 	[RPCAUTH_nfsd] = {
1193b3537c35SJeff Layton 		.name = "nfsd",
1194b3537c35SJeff Layton 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
1195b3537c35SJeff Layton 	},
11964b9a445eSJeff Layton 	[RPCAUTH_gssd] = {
11974b9a445eSJeff Layton 		.name = "gssd",
11984b9a445eSJeff Layton 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
11994b9a445eSJeff Layton 	},
1200bb156749STrond Myklebust };
1201bb156749STrond Myklebust 
1202432eb1a5SStanislav Kinsbursky /*
1203432eb1a5SStanislav Kinsbursky  * This call can be used only in RPC pipefs mount notification hooks.
1204432eb1a5SStanislav Kinsbursky  */
1205432eb1a5SStanislav Kinsbursky struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
1206432eb1a5SStanislav Kinsbursky 			       const unsigned char *dir_name)
1207432eb1a5SStanislav Kinsbursky {
120826fe5750SLinus Torvalds 	struct qstr dir = QSTR_INIT(dir_name, strlen(dir_name));
1209d3db90b0SAl Viro 	return d_hash_and_lookup(sb->s_root, &dir);
1210432eb1a5SStanislav Kinsbursky }
1211432eb1a5SStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
1212432eb1a5SStanislav Kinsbursky 
12134b9a445eSJeff Layton int rpc_pipefs_init_net(struct net *net)
1214c21a588fSStanislav Kinsbursky {
1215c21a588fSStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1216c21a588fSStanislav Kinsbursky 
12174b9a445eSJeff Layton 	sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0);
12184b9a445eSJeff Layton 	if (IS_ERR(sn->gssd_dummy))
12194b9a445eSJeff Layton 		return PTR_ERR(sn->gssd_dummy);
12204b9a445eSJeff Layton 
1221c21a588fSStanislav Kinsbursky 	mutex_init(&sn->pipefs_sb_lock);
12222aed8b47STrond Myklebust 	sn->pipe_version = -1;
12234b9a445eSJeff Layton 	return 0;
12244b9a445eSJeff Layton }
12254b9a445eSJeff Layton 
12264b9a445eSJeff Layton void rpc_pipefs_exit_net(struct net *net)
12274b9a445eSJeff Layton {
12284b9a445eSJeff Layton 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
12294b9a445eSJeff Layton 
12304b9a445eSJeff Layton 	rpc_destroy_pipe_data(sn->gssd_dummy);
1231c21a588fSStanislav Kinsbursky }
1232c21a588fSStanislav Kinsbursky 
1233c21a588fSStanislav Kinsbursky /*
1234c21a588fSStanislav Kinsbursky  * This call will be used for per network namespace operations calls.
1235c21a588fSStanislav Kinsbursky  * Note: Function will be returned with pipefs_sb_lock taken if superblock was
1236c21a588fSStanislav Kinsbursky  * found. This lock have to be released by rpc_put_sb_net() when all operations
1237c21a588fSStanislav Kinsbursky  * will be completed.
1238c21a588fSStanislav Kinsbursky  */
1239c21a588fSStanislav Kinsbursky struct super_block *rpc_get_sb_net(const struct net *net)
1240c21a588fSStanislav Kinsbursky {
1241c21a588fSStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1242c21a588fSStanislav Kinsbursky 
1243c21a588fSStanislav Kinsbursky 	mutex_lock(&sn->pipefs_sb_lock);
1244c21a588fSStanislav Kinsbursky 	if (sn->pipefs_sb)
1245c21a588fSStanislav Kinsbursky 		return sn->pipefs_sb;
1246c21a588fSStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1247c21a588fSStanislav Kinsbursky 	return NULL;
1248c21a588fSStanislav Kinsbursky }
1249c21a588fSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_get_sb_net);
1250c21a588fSStanislav Kinsbursky 
1251c21a588fSStanislav Kinsbursky void rpc_put_sb_net(const struct net *net)
1252c21a588fSStanislav Kinsbursky {
1253c21a588fSStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1254c21a588fSStanislav Kinsbursky 
1255749386e9SWeston Andros Adamson 	WARN_ON(sn->pipefs_sb == NULL);
1256c21a588fSStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1257c21a588fSStanislav Kinsbursky }
1258c21a588fSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_put_sb_net);
1259c21a588fSStanislav Kinsbursky 
12604b9a445eSJeff Layton static const struct rpc_filelist gssd_dummy_clnt_dir[] = {
12614b9a445eSJeff Layton 	[0] = {
12624b9a445eSJeff Layton 		.name = "clntXX",
12634b9a445eSJeff Layton 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
12644b9a445eSJeff Layton 	},
12654b9a445eSJeff Layton };
12664b9a445eSJeff Layton 
12674b9a445eSJeff Layton static ssize_t
12684b9a445eSJeff Layton dummy_downcall(struct file *filp, const char __user *src, size_t len)
12694b9a445eSJeff Layton {
12704b9a445eSJeff Layton 	return -EINVAL;
12714b9a445eSJeff Layton }
12724b9a445eSJeff Layton 
12734b9a445eSJeff Layton static const struct rpc_pipe_ops gssd_dummy_pipe_ops = {
12744b9a445eSJeff Layton 	.upcall		= rpc_pipe_generic_upcall,
12754b9a445eSJeff Layton 	.downcall	= dummy_downcall,
12764b9a445eSJeff Layton };
12774b9a445eSJeff Layton 
12784b9a445eSJeff Layton /**
12794b9a445eSJeff Layton  * rpc_gssd_dummy_populate - create a dummy gssd pipe
12804b9a445eSJeff Layton  * @root:	root of the rpc_pipefs filesystem
12814b9a445eSJeff Layton  * @pipe_data:	pipe data created when netns is initialized
12824b9a445eSJeff Layton  *
12834b9a445eSJeff Layton  * Create a dummy set of directories and a pipe that gssd can hold open to
12844b9a445eSJeff Layton  * indicate that it is up and running.
12854b9a445eSJeff Layton  */
12864b9a445eSJeff Layton static struct dentry *
12874b9a445eSJeff Layton rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
12884b9a445eSJeff Layton {
12894b9a445eSJeff Layton 	int ret = 0;
12904b9a445eSJeff Layton 	struct dentry *gssd_dentry;
12914b9a445eSJeff Layton 	struct dentry *clnt_dentry = NULL;
12924b9a445eSJeff Layton 	struct dentry *pipe_dentry = NULL;
12934b9a445eSJeff Layton 	struct qstr q = QSTR_INIT(files[RPCAUTH_gssd].name,
12944b9a445eSJeff Layton 				  strlen(files[RPCAUTH_gssd].name));
12954b9a445eSJeff Layton 
12964b9a445eSJeff Layton 	/* We should never get this far if "gssd" doesn't exist */
12974b9a445eSJeff Layton 	gssd_dentry = d_hash_and_lookup(root, &q);
12984b9a445eSJeff Layton 	if (!gssd_dentry)
12994b9a445eSJeff Layton 		return ERR_PTR(-ENOENT);
13004b9a445eSJeff Layton 
13014b9a445eSJeff Layton 	ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL);
13024b9a445eSJeff Layton 	if (ret) {
13034b9a445eSJeff Layton 		pipe_dentry = ERR_PTR(ret);
13044b9a445eSJeff Layton 		goto out;
13054b9a445eSJeff Layton 	}
13064b9a445eSJeff Layton 
13074b9a445eSJeff Layton 	q.name = gssd_dummy_clnt_dir[0].name;
13084b9a445eSJeff Layton 	q.len = strlen(gssd_dummy_clnt_dir[0].name);
13094b9a445eSJeff Layton 	clnt_dentry = d_hash_and_lookup(gssd_dentry, &q);
13104b9a445eSJeff Layton 	if (!clnt_dentry) {
13114b9a445eSJeff Layton 		pipe_dentry = ERR_PTR(-ENOENT);
13124b9a445eSJeff Layton 		goto out;
13134b9a445eSJeff Layton 	}
13144b9a445eSJeff Layton 
13154b9a445eSJeff Layton 	pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data);
13163396f92fSJeff Layton 	if (IS_ERR(pipe_dentry))
13173396f92fSJeff Layton 		__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
13184b9a445eSJeff Layton out:
13194b9a445eSJeff Layton 	dput(clnt_dentry);
13204b9a445eSJeff Layton 	dput(gssd_dentry);
13214b9a445eSJeff Layton 	return pipe_dentry;
13224b9a445eSJeff Layton }
13234b9a445eSJeff Layton 
13241da177e4SLinus Torvalds static int
13251da177e4SLinus Torvalds rpc_fill_super(struct super_block *sb, void *data, int silent)
13261da177e4SLinus Torvalds {
13271da177e4SLinus Torvalds 	struct inode *inode;
13284b9a445eSJeff Layton 	struct dentry *root, *gssd_dentry;
132938b0da75SStanislav Kinsbursky 	struct net *net = data;
133090c4e829SStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
13312d00131aSStanislav Kinsbursky 	int err;
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds 	sb->s_blocksize = PAGE_CACHE_SIZE;
13341da177e4SLinus Torvalds 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
13351da177e4SLinus Torvalds 	sb->s_magic = RPCAUTH_GSSMAGIC;
13361da177e4SLinus Torvalds 	sb->s_op = &s_ops;
1337b26d4cd3SAl Viro 	sb->s_d_op = &simple_dentry_operations;
13381da177e4SLinus Torvalds 	sb->s_time_gran = 1;
13391da177e4SLinus Torvalds 
13407e450b4eSJeff Layton 	inode = rpc_get_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
134148fde701SAl Viro 	sb->s_root = root = d_make_root(inode);
134248fde701SAl Viro 	if (!root)
13431da177e4SLinus Torvalds 		return -ENOMEM;
1344ac6feceeSTrond Myklebust 	if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
13451da177e4SLinus Torvalds 		return -ENOMEM;
13464b9a445eSJeff Layton 
13474b9a445eSJeff Layton 	gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy);
13484b9a445eSJeff Layton 	if (IS_ERR(gssd_dentry)) {
13494b9a445eSJeff Layton 		__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
13504b9a445eSJeff Layton 		return PTR_ERR(gssd_dentry);
13514b9a445eSJeff Layton 	}
13524b9a445eSJeff Layton 
1353d8af9bc1SChuck Lever 	dprintk("RPC:       sending pipefs MOUNT notification for net %p%s\n",
1354d8af9bc1SChuck Lever 		net, NET_NAME(net));
135538481605SStanislav Kinsbursky 	mutex_lock(&sn->pipefs_sb_lock);
135637629b57SStanislav Kinsbursky 	sn->pipefs_sb = sb;
13572d00131aSStanislav Kinsbursky 	err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
13582d00131aSStanislav Kinsbursky 					   RPC_PIPEFS_MOUNT,
13592d00131aSStanislav Kinsbursky 					   sb);
13602d00131aSStanislav Kinsbursky 	if (err)
13612d00131aSStanislav Kinsbursky 		goto err_depopulate;
1362021c68deSStanislav Kinsbursky 	sb->s_fs_info = get_net(net);
136338481605SStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1364fc7bed8cSAl Viro 	return 0;
13652d00131aSStanislav Kinsbursky 
13662d00131aSStanislav Kinsbursky err_depopulate:
13674b9a445eSJeff Layton 	dput(gssd_dentry);
13682d00131aSStanislav Kinsbursky 	blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
13692d00131aSStanislav Kinsbursky 					   RPC_PIPEFS_UMOUNT,
13702d00131aSStanislav Kinsbursky 					   sb);
137137629b57SStanislav Kinsbursky 	sn->pipefs_sb = NULL;
13722d00131aSStanislav Kinsbursky 	__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
137338481605SStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
13742d00131aSStanislav Kinsbursky 	return err;
13751da177e4SLinus Torvalds }
13761da177e4SLinus Torvalds 
137789f84243SJeff Layton bool
137889f84243SJeff Layton gssd_running(struct net *net)
137989f84243SJeff Layton {
138089f84243SJeff Layton 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
138189f84243SJeff Layton 	struct rpc_pipe *pipe = sn->gssd_dummy;
138289f84243SJeff Layton 
138389f84243SJeff Layton 	return pipe->nreaders || pipe->nwriters;
138489f84243SJeff Layton }
138589f84243SJeff Layton EXPORT_SYMBOL_GPL(gssd_running);
138689f84243SJeff Layton 
1387fc14f2feSAl Viro static struct dentry *
1388fc14f2feSAl Viro rpc_mount(struct file_system_type *fs_type,
1389fc14f2feSAl Viro 		int flags, const char *dev_name, void *data)
13901da177e4SLinus Torvalds {
139138b0da75SStanislav Kinsbursky 	return mount_ns(fs_type, flags, current->nsproxy->net_ns, rpc_fill_super);
13921da177e4SLinus Torvalds }
13931da177e4SLinus Torvalds 
139409acfea5STrond Myklebust static void rpc_kill_sb(struct super_block *sb)
1395021c68deSStanislav Kinsbursky {
1396021c68deSStanislav Kinsbursky 	struct net *net = sb->s_fs_info;
139790c4e829SStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1398021c68deSStanislav Kinsbursky 
1399c21a588fSStanislav Kinsbursky 	mutex_lock(&sn->pipefs_sb_lock);
1400642fe4d0STrond Myklebust 	if (sn->pipefs_sb != sb) {
1401642fe4d0STrond Myklebust 		mutex_unlock(&sn->pipefs_sb_lock);
1402642fe4d0STrond Myklebust 		goto out;
1403642fe4d0STrond Myklebust 	}
140490c4e829SStanislav Kinsbursky 	sn->pipefs_sb = NULL;
1405d8af9bc1SChuck Lever 	dprintk("RPC:       sending pipefs UMOUNT notification for net %p%s\n",
1406d8af9bc1SChuck Lever 		net, NET_NAME(net));
14072d00131aSStanislav Kinsbursky 	blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
14082d00131aSStanislav Kinsbursky 					   RPC_PIPEFS_UMOUNT,
14092d00131aSStanislav Kinsbursky 					   sb);
1410adb6fa7fSStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1411642fe4d0STrond Myklebust 	put_net(net);
1412642fe4d0STrond Myklebust out:
1413021c68deSStanislav Kinsbursky 	kill_litter_super(sb);
14141da177e4SLinus Torvalds }
14151da177e4SLinus Torvalds 
14161da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type = {
14171da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
14181da177e4SLinus Torvalds 	.name		= "rpc_pipefs",
1419fc14f2feSAl Viro 	.mount		= rpc_mount,
1420021c68deSStanislav Kinsbursky 	.kill_sb	= rpc_kill_sb,
14211da177e4SLinus Torvalds };
14227f78e035SEric W. Biederman MODULE_ALIAS_FS("rpc_pipefs");
1423fa7614ddSEric W. Biederman MODULE_ALIAS("rpc_pipefs");
14241da177e4SLinus Torvalds 
14251da177e4SLinus Torvalds static void
142651cc5068SAlexey Dobriyan init_once(void *foo)
14271da177e4SLinus Torvalds {
14281da177e4SLinus Torvalds 	struct rpc_inode *rpci = (struct rpc_inode *) foo;
14291da177e4SLinus Torvalds 
14301da177e4SLinus Torvalds 	inode_init_once(&rpci->vfs_inode);
14311da177e4SLinus Torvalds 	rpci->private = NULL;
1432ba9e0975SStanislav Kinsbursky 	rpci->pipe = NULL;
14331da177e4SLinus Torvalds 	init_waitqueue_head(&rpci->waitq);
14341da177e4SLinus Torvalds }
14351da177e4SLinus Torvalds 
14361da177e4SLinus Torvalds int register_rpc_pipefs(void)
14371da177e4SLinus Torvalds {
14385bd5f581SAkinobu Mita 	int err;
14395bd5f581SAkinobu Mita 
14401da177e4SLinus Torvalds 	rpc_inode_cachep = kmem_cache_create("rpc_inode_cache",
14411da177e4SLinus Torvalds 				sizeof(struct rpc_inode),
1442fffb60f9SPaul Jackson 				0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
1443fffb60f9SPaul Jackson 						SLAB_MEM_SPREAD),
144420c2df83SPaul Mundt 				init_once);
14451da177e4SLinus Torvalds 	if (!rpc_inode_cachep)
14461da177e4SLinus Torvalds 		return -ENOMEM;
144780df9d20SStanislav Kinsbursky 	err = rpc_clients_notifier_register();
144880df9d20SStanislav Kinsbursky 	if (err)
144980df9d20SStanislav Kinsbursky 		goto err_notifier;
14505bd5f581SAkinobu Mita 	err = register_filesystem(&rpc_pipe_fs_type);
145180df9d20SStanislav Kinsbursky 	if (err)
145280df9d20SStanislav Kinsbursky 		goto err_register;
145380df9d20SStanislav Kinsbursky 	return 0;
145480df9d20SStanislav Kinsbursky 
145580df9d20SStanislav Kinsbursky err_register:
145680df9d20SStanislav Kinsbursky 	rpc_clients_notifier_unregister();
145780df9d20SStanislav Kinsbursky err_notifier:
14585bd5f581SAkinobu Mita 	kmem_cache_destroy(rpc_inode_cachep);
14595bd5f581SAkinobu Mita 	return err;
14605bd5f581SAkinobu Mita }
14615bd5f581SAkinobu Mita 
14621da177e4SLinus Torvalds void unregister_rpc_pipefs(void)
14631da177e4SLinus Torvalds {
146480df9d20SStanislav Kinsbursky 	rpc_clients_notifier_unregister();
14651a1d92c1SAlexey Dobriyan 	kmem_cache_destroy(rpc_inode_cachep);
14661da177e4SLinus Torvalds 	unregister_filesystem(&rpc_pipe_fs_type);
14671da177e4SLinus Torvalds }
1468