xref: /openbmc/linux/net/sunrpc/rpc_pipe.c (revision b7ade381)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * net/sunrpc/rpc_pipe.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Userland/kernel interface for rpcauth_gss.
61da177e4SLinus Torvalds  * Code shamelessly plagiarized from fs/nfsd/nfsctl.c
7d51fe1beSRolf Eike Beer  * and fs/sysfs/inode.c
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no>
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds #include <linux/module.h>
131da177e4SLinus Torvalds #include <linux/slab.h>
141da177e4SLinus Torvalds #include <linux/string.h>
151da177e4SLinus Torvalds #include <linux/pagemap.h>
161da177e4SLinus Torvalds #include <linux/mount.h>
17b9662f31SDavid Howells #include <linux/fs_context.h>
181da177e4SLinus Torvalds #include <linux/namei.h>
1950e437d5STrond Myklebust #include <linux/fsnotify.h>
201da177e4SLinus Torvalds #include <linux/kernel.h>
212446ab60STrond Myklebust #include <linux/rcupdate.h>
22e2f0c83aSJeff Layton #include <linux/utsname.h>
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds #include <asm/ioctls.h>
251da177e4SLinus Torvalds #include <linux/poll.h>
261da177e4SLinus Torvalds #include <linux/wait.h>
271da177e4SLinus Torvalds #include <linux/seq_file.h>
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
301da177e4SLinus Torvalds #include <linux/workqueue.h>
311da177e4SLinus Torvalds #include <linux/sunrpc/rpc_pipe_fs.h>
328854e82dSTrond Myklebust #include <linux/sunrpc/cache.h>
33021c68deSStanislav Kinsbursky #include <linux/nsproxy.h>
342d00131aSStanislav Kinsbursky #include <linux/notifier.h>
351da177e4SLinus Torvalds 
36021c68deSStanislav Kinsbursky #include "netns.h"
372d00131aSStanislav Kinsbursky #include "sunrpc.h"
381da177e4SLinus Torvalds 
39efc46bf2SStanislav Kinsbursky #define RPCDBG_FACILITY RPCDBG_DEBUG
40efc46bf2SStanislav Kinsbursky 
41efc46bf2SStanislav Kinsbursky #define NET_NAME(net)	((net == &init_net) ? " (init_net)" : "")
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type;
444b9a445eSJeff Layton static const struct rpc_pipe_ops gssd_dummy_pipe_ops;
451da177e4SLinus Torvalds 
46e18b890bSChristoph Lameter static struct kmem_cache *rpc_inode_cachep __read_mostly;
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds #define RPC_UPCALL_TIMEOUT (30*HZ)
491da177e4SLinus Torvalds 
502d00131aSStanislav Kinsbursky static BLOCKING_NOTIFIER_HEAD(rpc_pipefs_notifier_list);
512d00131aSStanislav Kinsbursky 
522d00131aSStanislav Kinsbursky int rpc_pipefs_notifier_register(struct notifier_block *nb)
532d00131aSStanislav Kinsbursky {
54260a2679SXiaoming Ni 	return blocking_notifier_chain_register(&rpc_pipefs_notifier_list, nb);
552d00131aSStanislav Kinsbursky }
562d00131aSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_register);
572d00131aSStanislav Kinsbursky 
582d00131aSStanislav Kinsbursky void rpc_pipefs_notifier_unregister(struct notifier_block *nb)
592d00131aSStanislav Kinsbursky {
602d00131aSStanislav Kinsbursky 	blocking_notifier_chain_unregister(&rpc_pipefs_notifier_list, nb);
612d00131aSStanislav Kinsbursky }
622d00131aSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister);
632d00131aSStanislav Kinsbursky 
64591ad7feSStanislav Kinsbursky static void rpc_purge_list(wait_queue_head_t *waitq, struct list_head *head,
659842ef35STrond Myklebust 		void (*destroy_msg)(struct rpc_pipe_msg *), int err)
66b3eb67a2STrond Myklebust {
67b3eb67a2STrond Myklebust 	struct rpc_pipe_msg *msg;
68b3eb67a2STrond Myklebust 
699842ef35STrond Myklebust 	if (list_empty(head))
709842ef35STrond Myklebust 		return;
719842ef35STrond Myklebust 	do {
72b3eb67a2STrond Myklebust 		msg = list_entry(head->next, struct rpc_pipe_msg, list);
735a67657aSTrond Myklebust 		list_del_init(&msg->list);
74b3eb67a2STrond Myklebust 		msg->errno = err;
75b3eb67a2STrond Myklebust 		destroy_msg(msg);
769842ef35STrond Myklebust 	} while (!list_empty(head));
7792123e06SJeff Layton 
7892123e06SJeff Layton 	if (waitq)
79591ad7feSStanislav Kinsbursky 		wake_up(waitq);
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds static void
8365f27f38SDavid Howells rpc_timeout_upcall_queue(struct work_struct *work)
841da177e4SLinus Torvalds {
859842ef35STrond Myklebust 	LIST_HEAD(free_list);
86ba9e0975SStanislav Kinsbursky 	struct rpc_pipe *pipe =
87ba9e0975SStanislav Kinsbursky 		container_of(work, struct rpc_pipe, queue_timeout.work);
889842ef35STrond Myklebust 	void (*destroy_msg)(struct rpc_pipe_msg *);
89591ad7feSStanislav Kinsbursky 	struct dentry *dentry;
901da177e4SLinus Torvalds 
91ba9e0975SStanislav Kinsbursky 	spin_lock(&pipe->lock);
92ba9e0975SStanislav Kinsbursky 	destroy_msg = pipe->ops->destroy_msg;
93ba9e0975SStanislav Kinsbursky 	if (pipe->nreaders == 0) {
94ba9e0975SStanislav Kinsbursky 		list_splice_init(&pipe->pipe, &free_list);
95ba9e0975SStanislav Kinsbursky 		pipe->pipelen = 0;
969842ef35STrond Myklebust 	}
97591ad7feSStanislav Kinsbursky 	dentry = dget(pipe->dentry);
98ba9e0975SStanislav Kinsbursky 	spin_unlock(&pipe->lock);
99c5ef6035SDavid Howells 	rpc_purge_list(dentry ? &RPC_I(d_inode(dentry))->waitq : NULL,
100591ad7feSStanislav Kinsbursky 			&free_list, destroy_msg, -ETIMEDOUT);
101591ad7feSStanislav Kinsbursky 	dput(dentry);
1029842ef35STrond Myklebust }
1031da177e4SLinus Torvalds 
104c1225158SPeng Tao ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg,
105c1225158SPeng Tao 				char __user *dst, size_t buflen)
106c1225158SPeng Tao {
107c1225158SPeng Tao 	char *data = (char *)msg->data + msg->copied;
108c1225158SPeng Tao 	size_t mlen = min(msg->len - msg->copied, buflen);
109c1225158SPeng Tao 	unsigned long left;
110c1225158SPeng Tao 
111c1225158SPeng Tao 	left = copy_to_user(dst, data, mlen);
112c1225158SPeng Tao 	if (left == mlen) {
113c1225158SPeng Tao 		msg->errno = -EFAULT;
114c1225158SPeng Tao 		return -EFAULT;
115c1225158SPeng Tao 	}
116c1225158SPeng Tao 
117c1225158SPeng Tao 	mlen -= left;
118c1225158SPeng Tao 	msg->copied += mlen;
119c1225158SPeng Tao 	msg->errno = 0;
120c1225158SPeng Tao 	return mlen;
121c1225158SPeng Tao }
122c1225158SPeng Tao EXPORT_SYMBOL_GPL(rpc_pipe_generic_upcall);
123c1225158SPeng Tao 
12493a44a75SJ. Bruce Fields /**
1251a5778aaSBen Hutchings  * rpc_queue_upcall - queue an upcall message to userspace
126bda14606SRandy Dunlap  * @pipe: upcall pipe on which to queue given message
12793a44a75SJ. Bruce Fields  * @msg: message to queue
12893a44a75SJ. Bruce Fields  *
12993a44a75SJ. Bruce Fields  * Call with an @inode created by rpc_mkpipe() to queue an upcall.
13093a44a75SJ. Bruce Fields  * A userspace process may then later read the upcall by performing a
13193a44a75SJ. Bruce Fields  * read on an open file for this inode.  It is up to the caller to
13293a44a75SJ. Bruce Fields  * initialize the fields of @msg (other than @msg->list) appropriately.
13393a44a75SJ. Bruce Fields  */
1341da177e4SLinus Torvalds int
135d706ed1fSStanislav Kinsbursky rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg)
1361da177e4SLinus Torvalds {
1376070fe6fSTrond Myklebust 	int res = -EPIPE;
138591ad7feSStanislav Kinsbursky 	struct dentry *dentry;
1391da177e4SLinus Torvalds 
140d0fe13baSStanislav Kinsbursky 	spin_lock(&pipe->lock);
141d0fe13baSStanislav Kinsbursky 	if (pipe->nreaders) {
142d0fe13baSStanislav Kinsbursky 		list_add_tail(&msg->list, &pipe->pipe);
143d0fe13baSStanislav Kinsbursky 		pipe->pipelen += msg->len;
1446070fe6fSTrond Myklebust 		res = 0;
145d0fe13baSStanislav Kinsbursky 	} else if (pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) {
146d0fe13baSStanislav Kinsbursky 		if (list_empty(&pipe->pipe))
14724c5d9d7STrond Myklebust 			queue_delayed_work(rpciod_workqueue,
148d0fe13baSStanislav Kinsbursky 					&pipe->queue_timeout,
1491da177e4SLinus Torvalds 					RPC_UPCALL_TIMEOUT);
150d0fe13baSStanislav Kinsbursky 		list_add_tail(&msg->list, &pipe->pipe);
151d0fe13baSStanislav Kinsbursky 		pipe->pipelen += msg->len;
1526070fe6fSTrond Myklebust 		res = 0;
1536070fe6fSTrond Myklebust 	}
154591ad7feSStanislav Kinsbursky 	dentry = dget(pipe->dentry);
155d0fe13baSStanislav Kinsbursky 	spin_unlock(&pipe->lock);
156591ad7feSStanislav Kinsbursky 	if (dentry) {
157c5ef6035SDavid Howells 		wake_up(&RPC_I(d_inode(dentry))->waitq);
158591ad7feSStanislav Kinsbursky 		dput(dentry);
159591ad7feSStanislav Kinsbursky 	}
1601da177e4SLinus Torvalds 	return res;
1611da177e4SLinus Torvalds }
162468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_queue_upcall);
1631da177e4SLinus Torvalds 
1646070fe6fSTrond Myklebust static inline void
1656070fe6fSTrond Myklebust rpc_inode_setowner(struct inode *inode, void *private)
1666070fe6fSTrond Myklebust {
1676070fe6fSTrond Myklebust 	RPC_I(inode)->private = private;
1686070fe6fSTrond Myklebust }
1696070fe6fSTrond Myklebust 
1701da177e4SLinus Torvalds static void
1711da177e4SLinus Torvalds rpc_close_pipes(struct inode *inode)
1721da177e4SLinus Torvalds {
173ba9e0975SStanislav Kinsbursky 	struct rpc_pipe *pipe = RPC_I(inode)->pipe;
174e712804aS\"J. Bruce Fields\ 	int need_release;
175ad6b1340SStanislav Kinsbursky 	LIST_HEAD(free_list);
1761da177e4SLinus Torvalds 
1775955102cSAl Viro 	inode_lock(inode);
178ba9e0975SStanislav Kinsbursky 	spin_lock(&pipe->lock);
179ba9e0975SStanislav Kinsbursky 	need_release = pipe->nreaders != 0 || pipe->nwriters != 0;
180ba9e0975SStanislav Kinsbursky 	pipe->nreaders = 0;
181ba9e0975SStanislav Kinsbursky 	list_splice_init(&pipe->in_upcall, &free_list);
182ba9e0975SStanislav Kinsbursky 	list_splice_init(&pipe->pipe, &free_list);
183ba9e0975SStanislav Kinsbursky 	pipe->pipelen = 0;
184ad6b1340SStanislav Kinsbursky 	pipe->dentry = NULL;
185ba9e0975SStanislav Kinsbursky 	spin_unlock(&pipe->lock);
186591ad7feSStanislav Kinsbursky 	rpc_purge_list(&RPC_I(inode)->waitq, &free_list, pipe->ops->destroy_msg, -EPIPE);
187ba9e0975SStanislav Kinsbursky 	pipe->nwriters = 0;
188ad6b1340SStanislav Kinsbursky 	if (need_release && pipe->ops->release_pipe)
189ad6b1340SStanislav Kinsbursky 		pipe->ops->release_pipe(inode);
190ba9e0975SStanislav Kinsbursky 	cancel_delayed_work_sync(&pipe->queue_timeout);
1916070fe6fSTrond Myklebust 	rpc_inode_setowner(inode, NULL);
1922c9030eeSStanislav Kinsbursky 	RPC_I(inode)->pipe = NULL;
1935955102cSAl Viro 	inode_unlock(inode);
1941da177e4SLinus Torvalds }
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds static struct inode *
1971da177e4SLinus Torvalds rpc_alloc_inode(struct super_block *sb)
1981da177e4SLinus Torvalds {
1991da177e4SLinus Torvalds 	struct rpc_inode *rpci;
200adcda652SHimangi Saraogi 	rpci = kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL);
2011da177e4SLinus Torvalds 	if (!rpci)
2021da177e4SLinus Torvalds 		return NULL;
2031da177e4SLinus Torvalds 	return &rpci->vfs_inode;
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds static void
207bef252faSAl Viro rpc_free_inode(struct inode *inode)
208fa0d7e3dSNick Piggin {
209fa0d7e3dSNick Piggin 	kmem_cache_free(rpc_inode_cachep, RPC_I(inode));
210fa0d7e3dSNick Piggin }
211fa0d7e3dSNick Piggin 
2121da177e4SLinus Torvalds static int
2131da177e4SLinus Torvalds rpc_pipe_open(struct inode *inode, struct file *filp)
2141da177e4SLinus Torvalds {
2152c9030eeSStanislav Kinsbursky 	struct rpc_pipe *pipe;
216c3810608S\"J. Bruce Fields\ 	int first_open;
2171da177e4SLinus Torvalds 	int res = -ENXIO;
2181da177e4SLinus Torvalds 
2195955102cSAl Viro 	inode_lock(inode);
2202c9030eeSStanislav Kinsbursky 	pipe = RPC_I(inode)->pipe;
2212c9030eeSStanislav Kinsbursky 	if (pipe == NULL)
222c3810608S\"J. Bruce Fields\ 		goto out;
223d0fe13baSStanislav Kinsbursky 	first_open = pipe->nreaders == 0 && pipe->nwriters == 0;
224d0fe13baSStanislav Kinsbursky 	if (first_open && pipe->ops->open_pipe) {
225d0fe13baSStanislav Kinsbursky 		res = pipe->ops->open_pipe(inode);
226c3810608S\"J. Bruce Fields\ 		if (res)
227c3810608S\"J. Bruce Fields\ 			goto out;
228c3810608S\"J. Bruce Fields\ 	}
2291da177e4SLinus Torvalds 	if (filp->f_mode & FMODE_READ)
230d0fe13baSStanislav Kinsbursky 		pipe->nreaders++;
2311da177e4SLinus Torvalds 	if (filp->f_mode & FMODE_WRITE)
232d0fe13baSStanislav Kinsbursky 		pipe->nwriters++;
2331da177e4SLinus Torvalds 	res = 0;
234c3810608S\"J. Bruce Fields\ out:
2355955102cSAl Viro 	inode_unlock(inode);
2361da177e4SLinus Torvalds 	return res;
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds static int
2401da177e4SLinus Torvalds rpc_pipe_release(struct inode *inode, struct file *filp)
2411da177e4SLinus Torvalds {
2422c9030eeSStanislav Kinsbursky 	struct rpc_pipe *pipe;
2431da177e4SLinus Torvalds 	struct rpc_pipe_msg *msg;
244e712804aS\"J. Bruce Fields\ 	int last_close;
2451da177e4SLinus Torvalds 
2465955102cSAl Viro 	inode_lock(inode);
2472c9030eeSStanislav Kinsbursky 	pipe = RPC_I(inode)->pipe;
2482c9030eeSStanislav Kinsbursky 	if (pipe == NULL)
2491da177e4SLinus Torvalds 		goto out;
250655b5bb4SJoe Perches 	msg = filp->private_data;
2511da177e4SLinus Torvalds 	if (msg != NULL) {
252ba9e0975SStanislav Kinsbursky 		spin_lock(&pipe->lock);
25348e49187STrond Myklebust 		msg->errno = -EAGAIN;
2545a67657aSTrond Myklebust 		list_del_init(&msg->list);
255ba9e0975SStanislav Kinsbursky 		spin_unlock(&pipe->lock);
256ba9e0975SStanislav Kinsbursky 		pipe->ops->destroy_msg(msg);
2571da177e4SLinus Torvalds 	}
2581da177e4SLinus Torvalds 	if (filp->f_mode & FMODE_WRITE)
259ba9e0975SStanislav Kinsbursky 		pipe->nwriters --;
2609842ef35STrond Myklebust 	if (filp->f_mode & FMODE_READ) {
261ba9e0975SStanislav Kinsbursky 		pipe->nreaders --;
262ba9e0975SStanislav Kinsbursky 		if (pipe->nreaders == 0) {
2639842ef35STrond Myklebust 			LIST_HEAD(free_list);
264ba9e0975SStanislav Kinsbursky 			spin_lock(&pipe->lock);
265ba9e0975SStanislav Kinsbursky 			list_splice_init(&pipe->pipe, &free_list);
266ba9e0975SStanislav Kinsbursky 			pipe->pipelen = 0;
267ba9e0975SStanislav Kinsbursky 			spin_unlock(&pipe->lock);
268591ad7feSStanislav Kinsbursky 			rpc_purge_list(&RPC_I(inode)->waitq, &free_list,
269ba9e0975SStanislav Kinsbursky 					pipe->ops->destroy_msg, -EAGAIN);
2709842ef35STrond Myklebust 		}
2719842ef35STrond Myklebust 	}
272ba9e0975SStanislav Kinsbursky 	last_close = pipe->nwriters == 0 && pipe->nreaders == 0;
273ba9e0975SStanislav Kinsbursky 	if (last_close && pipe->ops->release_pipe)
274ba9e0975SStanislav Kinsbursky 		pipe->ops->release_pipe(inode);
2751da177e4SLinus Torvalds out:
2765955102cSAl Viro 	inode_unlock(inode);
2771da177e4SLinus Torvalds 	return 0;
2781da177e4SLinus Torvalds }
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds static ssize_t
2811da177e4SLinus Torvalds rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
2821da177e4SLinus Torvalds {
283496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
2842c9030eeSStanislav Kinsbursky 	struct rpc_pipe *pipe;
2851da177e4SLinus Torvalds 	struct rpc_pipe_msg *msg;
2861da177e4SLinus Torvalds 	int res = 0;
2871da177e4SLinus Torvalds 
2885955102cSAl Viro 	inode_lock(inode);
2892c9030eeSStanislav Kinsbursky 	pipe = RPC_I(inode)->pipe;
2902c9030eeSStanislav Kinsbursky 	if (pipe == NULL) {
2911da177e4SLinus Torvalds 		res = -EPIPE;
2921da177e4SLinus Torvalds 		goto out_unlock;
2931da177e4SLinus Torvalds 	}
2941da177e4SLinus Torvalds 	msg = filp->private_data;
2951da177e4SLinus Torvalds 	if (msg == NULL) {
296d0fe13baSStanislav Kinsbursky 		spin_lock(&pipe->lock);
297d0fe13baSStanislav Kinsbursky 		if (!list_empty(&pipe->pipe)) {
298d0fe13baSStanislav Kinsbursky 			msg = list_entry(pipe->pipe.next,
2991da177e4SLinus Torvalds 					struct rpc_pipe_msg,
3001da177e4SLinus Torvalds 					list);
301d0fe13baSStanislav Kinsbursky 			list_move(&msg->list, &pipe->in_upcall);
302d0fe13baSStanislav Kinsbursky 			pipe->pipelen -= msg->len;
3031da177e4SLinus Torvalds 			filp->private_data = msg;
3041da177e4SLinus Torvalds 			msg->copied = 0;
3051da177e4SLinus Torvalds 		}
306d0fe13baSStanislav Kinsbursky 		spin_unlock(&pipe->lock);
3071da177e4SLinus Torvalds 		if (msg == NULL)
3081da177e4SLinus Torvalds 			goto out_unlock;
3091da177e4SLinus Torvalds 	}
3101da177e4SLinus Torvalds 	/* NOTE: it is up to the callback to update msg->copied */
311d0fe13baSStanislav Kinsbursky 	res = pipe->ops->upcall(filp, msg, buf, len);
3121da177e4SLinus Torvalds 	if (res < 0 || msg->len == msg->copied) {
3131da177e4SLinus Torvalds 		filp->private_data = NULL;
314d0fe13baSStanislav Kinsbursky 		spin_lock(&pipe->lock);
3155a67657aSTrond Myklebust 		list_del_init(&msg->list);
316d0fe13baSStanislav Kinsbursky 		spin_unlock(&pipe->lock);
317d0fe13baSStanislav Kinsbursky 		pipe->ops->destroy_msg(msg);
3181da177e4SLinus Torvalds 	}
3191da177e4SLinus Torvalds out_unlock:
3205955102cSAl Viro 	inode_unlock(inode);
3211da177e4SLinus Torvalds 	return res;
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds static ssize_t
3251da177e4SLinus Torvalds rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
3261da177e4SLinus Torvalds {
327496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
3281da177e4SLinus Torvalds 	int res;
3291da177e4SLinus Torvalds 
3305955102cSAl Viro 	inode_lock(inode);
3311da177e4SLinus Torvalds 	res = -EPIPE;
3322c9030eeSStanislav Kinsbursky 	if (RPC_I(inode)->pipe != NULL)
3332c9030eeSStanislav Kinsbursky 		res = RPC_I(inode)->pipe->ops->downcall(filp, buf, len);
3345955102cSAl Viro 	inode_unlock(inode);
3351da177e4SLinus Torvalds 	return res;
3361da177e4SLinus Torvalds }
3371da177e4SLinus Torvalds 
338ade994f4SAl Viro static __poll_t
3391da177e4SLinus Torvalds rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait)
3401da177e4SLinus Torvalds {
341496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
342591ad7feSStanislav Kinsbursky 	struct rpc_inode *rpci = RPC_I(inode);
343a9a08845SLinus Torvalds 	__poll_t mask = EPOLLOUT | EPOLLWRNORM;
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds 	poll_wait(filp, &rpci->waitq, wait);
3461da177e4SLinus Torvalds 
3475955102cSAl Viro 	inode_lock(inode);
348591ad7feSStanislav Kinsbursky 	if (rpci->pipe == NULL)
349a9a08845SLinus Torvalds 		mask |= EPOLLERR | EPOLLHUP;
350591ad7feSStanislav Kinsbursky 	else if (filp->private_data || !list_empty(&rpci->pipe->pipe))
351a9a08845SLinus Torvalds 		mask |= EPOLLIN | EPOLLRDNORM;
3525955102cSAl Viro 	inode_unlock(inode);
3531da177e4SLinus Torvalds 	return mask;
3541da177e4SLinus Torvalds }
3551da177e4SLinus Torvalds 
356a6f8dbc6SArnd Bergmann static long
357a6f8dbc6SArnd Bergmann rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
3581da177e4SLinus Torvalds {
359496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
3602c9030eeSStanislav Kinsbursky 	struct rpc_pipe *pipe;
3611da177e4SLinus Torvalds 	int len;
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 	switch (cmd) {
3641da177e4SLinus Torvalds 	case FIONREAD:
3655955102cSAl Viro 		inode_lock(inode);
3662c9030eeSStanislav Kinsbursky 		pipe = RPC_I(inode)->pipe;
3672c9030eeSStanislav Kinsbursky 		if (pipe == NULL) {
3685955102cSAl Viro 			inode_unlock(inode);
3691da177e4SLinus Torvalds 			return -EPIPE;
370a6f8dbc6SArnd Bergmann 		}
3712c9030eeSStanislav Kinsbursky 		spin_lock(&pipe->lock);
372d0fe13baSStanislav Kinsbursky 		len = pipe->pipelen;
3731da177e4SLinus Torvalds 		if (filp->private_data) {
3741da177e4SLinus Torvalds 			struct rpc_pipe_msg *msg;
375655b5bb4SJoe Perches 			msg = filp->private_data;
3761da177e4SLinus Torvalds 			len += msg->len - msg->copied;
3771da177e4SLinus Torvalds 		}
378d0fe13baSStanislav Kinsbursky 		spin_unlock(&pipe->lock);
3795955102cSAl Viro 		inode_unlock(inode);
3801da177e4SLinus Torvalds 		return put_user(len, (int __user *)arg);
3811da177e4SLinus Torvalds 	default:
3821da177e4SLinus Torvalds 		return -EINVAL;
3831da177e4SLinus Torvalds 	}
3841da177e4SLinus Torvalds }
3851da177e4SLinus Torvalds 
386da7071d7SArjan van de Ven static const struct file_operations rpc_pipe_fops = {
3871da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
3881da177e4SLinus Torvalds 	.llseek		= no_llseek,
3891da177e4SLinus Torvalds 	.read		= rpc_pipe_read,
3901da177e4SLinus Torvalds 	.write		= rpc_pipe_write,
3911da177e4SLinus Torvalds 	.poll		= rpc_pipe_poll,
392674b604cSFrederic Weisbecker 	.unlocked_ioctl	= rpc_pipe_ioctl,
3931da177e4SLinus Torvalds 	.open		= rpc_pipe_open,
3941da177e4SLinus Torvalds 	.release	= rpc_pipe_release,
3951da177e4SLinus Torvalds };
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds static int
3981da177e4SLinus Torvalds rpc_show_info(struct seq_file *m, void *v)
3991da177e4SLinus Torvalds {
4001da177e4SLinus Torvalds 	struct rpc_clnt *clnt = m->private;
4011da177e4SLinus Torvalds 
4022446ab60STrond Myklebust 	rcu_read_lock();
4034e0038b6STrond Myklebust 	seq_printf(m, "RPC server: %s\n",
4044e0038b6STrond Myklebust 			rcu_dereference(clnt->cl_xprt)->servername);
40555909f21STrond Myklebust 	seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_program->name,
4061da177e4SLinus Torvalds 			clnt->cl_prog, clnt->cl_vers);
407e7f78657SChuck Lever 	seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
408e7f78657SChuck Lever 	seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
409bf19aaceSJ. Bruce Fields 	seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT));
4102446ab60STrond Myklebust 	rcu_read_unlock();
4111da177e4SLinus Torvalds 	return 0;
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds static int
4151da177e4SLinus Torvalds rpc_info_open(struct inode *inode, struct file *file)
4161da177e4SLinus Torvalds {
417006abe88STrond Myklebust 	struct rpc_clnt *clnt = NULL;
4181da177e4SLinus Torvalds 	int ret = single_open(file, rpc_show_info, NULL);
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds 	if (!ret) {
4211da177e4SLinus Torvalds 		struct seq_file *m = file->private_data;
422006abe88STrond Myklebust 
423006abe88STrond Myklebust 		spin_lock(&file->f_path.dentry->d_lock);
424006abe88STrond Myklebust 		if (!d_unhashed(file->f_path.dentry))
4251da177e4SLinus Torvalds 			clnt = RPC_I(inode)->private;
426006abe88STrond Myklebust 		if (clnt != NULL && atomic_inc_not_zero(&clnt->cl_count)) {
427006abe88STrond Myklebust 			spin_unlock(&file->f_path.dentry->d_lock);
4281da177e4SLinus Torvalds 			m->private = clnt;
4291da177e4SLinus Torvalds 		} else {
430006abe88STrond Myklebust 			spin_unlock(&file->f_path.dentry->d_lock);
4311da177e4SLinus Torvalds 			single_release(inode, file);
4321da177e4SLinus Torvalds 			ret = -EINVAL;
4331da177e4SLinus Torvalds 		}
4341da177e4SLinus Torvalds 	}
4351da177e4SLinus Torvalds 	return ret;
4361da177e4SLinus Torvalds }
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds static int
4391da177e4SLinus Torvalds rpc_info_release(struct inode *inode, struct file *file)
4401da177e4SLinus Torvalds {
4411da177e4SLinus Torvalds 	struct seq_file *m = file->private_data;
4421da177e4SLinus Torvalds 	struct rpc_clnt *clnt = (struct rpc_clnt *)m->private;
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	if (clnt)
4451da177e4SLinus Torvalds 		rpc_release_client(clnt);
4461da177e4SLinus Torvalds 	return single_release(inode, file);
4471da177e4SLinus Torvalds }
4481da177e4SLinus Torvalds 
449da7071d7SArjan van de Ven static const struct file_operations rpc_info_operations = {
4501da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
4511da177e4SLinus Torvalds 	.open		= rpc_info_open,
4521da177e4SLinus Torvalds 	.read		= seq_read,
4531da177e4SLinus Torvalds 	.llseek		= seq_lseek,
4541da177e4SLinus Torvalds 	.release	= rpc_info_release,
4551da177e4SLinus Torvalds };
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds /*
4591da177e4SLinus Torvalds  * Description of fs contents.
4601da177e4SLinus Torvalds  */
4611da177e4SLinus Torvalds struct rpc_filelist {
462ac6feceeSTrond Myklebust 	const char *name;
46399ac48f5SArjan van de Ven 	const struct file_operations *i_fop;
4647364af6aSTrond Myklebust 	umode_t mode;
4651da177e4SLinus Torvalds };
4661da177e4SLinus Torvalds 
4671da177e4SLinus Torvalds static struct inode *
4687364af6aSTrond Myklebust rpc_get_inode(struct super_block *sb, umode_t mode)
4691da177e4SLinus Torvalds {
4701da177e4SLinus Torvalds 	struct inode *inode = new_inode(sb);
4711da177e4SLinus Torvalds 	if (!inode)
4721da177e4SLinus Torvalds 		return NULL;
47385fe4025SChristoph Hellwig 	inode->i_ino = get_next_ino();
4741da177e4SLinus Torvalds 	inode->i_mode = mode;
475078cd827SDeepa Dinamani 	inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
4761da177e4SLinus Torvalds 	switch (mode & S_IFMT) {
4771da177e4SLinus Torvalds 	case S_IFDIR:
4781da177e4SLinus Torvalds 		inode->i_fop = &simple_dir_operations;
479275448ebSJeff Layton 		inode->i_op = &simple_dir_inode_operations;
480d8c76e6fSDave Hansen 		inc_nlink(inode);
4811da177e4SLinus Torvalds 	default:
4821da177e4SLinus Torvalds 		break;
4831da177e4SLinus Torvalds 	}
4841da177e4SLinus Torvalds 	return inode;
4851da177e4SLinus Torvalds }
4861da177e4SLinus Torvalds 
4877589806eSTrond Myklebust static int __rpc_create_common(struct inode *dir, struct dentry *dentry,
4887589806eSTrond Myklebust 			       umode_t mode,
4897589806eSTrond Myklebust 			       const struct file_operations *i_fop,
4907589806eSTrond Myklebust 			       void *private)
4917589806eSTrond Myklebust {
4927589806eSTrond Myklebust 	struct inode *inode;
4937589806eSTrond Myklebust 
494beb0f0a9STrond Myklebust 	d_drop(dentry);
4957589806eSTrond Myklebust 	inode = rpc_get_inode(dir->i_sb, mode);
4967589806eSTrond Myklebust 	if (!inode)
4977589806eSTrond Myklebust 		goto out_err;
4987589806eSTrond Myklebust 	inode->i_ino = iunique(dir->i_sb, 100);
4997589806eSTrond Myklebust 	if (i_fop)
5007589806eSTrond Myklebust 		inode->i_fop = i_fop;
5017589806eSTrond Myklebust 	if (private)
5027589806eSTrond Myklebust 		rpc_inode_setowner(inode, private);
5037589806eSTrond Myklebust 	d_add(dentry, inode);
5047589806eSTrond Myklebust 	return 0;
5057589806eSTrond Myklebust out_err:
5061e903edaSAl Viro 	printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %pd\n",
5071e903edaSAl Viro 			__FILE__, __func__, dentry);
5087589806eSTrond Myklebust 	dput(dentry);
5097589806eSTrond Myklebust 	return -ENOMEM;
5107589806eSTrond Myklebust }
5117589806eSTrond Myklebust 
512ac6feceeSTrond Myklebust static int __rpc_create(struct inode *dir, struct dentry *dentry,
513ac6feceeSTrond Myklebust 			umode_t mode,
514ac6feceeSTrond Myklebust 			const struct file_operations *i_fop,
515ac6feceeSTrond Myklebust 			void *private)
516ac6feceeSTrond Myklebust {
517ac6feceeSTrond Myklebust 	int err;
518ac6feceeSTrond Myklebust 
519ac6feceeSTrond Myklebust 	err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private);
520ac6feceeSTrond Myklebust 	if (err)
521ac6feceeSTrond Myklebust 		return err;
522ac6feceeSTrond Myklebust 	fsnotify_create(dir, dentry);
523ac6feceeSTrond Myklebust 	return 0;
524ac6feceeSTrond Myklebust }
525ac6feceeSTrond Myklebust 
5267589806eSTrond Myklebust static int __rpc_mkdir(struct inode *dir, struct dentry *dentry,
5277589806eSTrond Myklebust 		       umode_t mode,
5287589806eSTrond Myklebust 		       const struct file_operations *i_fop,
5297589806eSTrond Myklebust 		       void *private)
5307589806eSTrond Myklebust {
5317589806eSTrond Myklebust 	int err;
5327589806eSTrond Myklebust 
5337589806eSTrond Myklebust 	err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private);
5347589806eSTrond Myklebust 	if (err)
5357589806eSTrond Myklebust 		return err;
5367589806eSTrond Myklebust 	inc_nlink(dir);
5377589806eSTrond Myklebust 	fsnotify_mkdir(dir, dentry);
5387589806eSTrond Myklebust 	return 0;
5397589806eSTrond Myklebust }
5407589806eSTrond Myklebust 
541ba9e0975SStanislav Kinsbursky static void
542ba9e0975SStanislav Kinsbursky init_pipe(struct rpc_pipe *pipe)
543ba9e0975SStanislav Kinsbursky {
544ba9e0975SStanislav Kinsbursky 	pipe->nreaders = 0;
545ba9e0975SStanislav Kinsbursky 	pipe->nwriters = 0;
546ba9e0975SStanislav Kinsbursky 	INIT_LIST_HEAD(&pipe->in_upcall);
547ba9e0975SStanislav Kinsbursky 	INIT_LIST_HEAD(&pipe->in_downcall);
548ba9e0975SStanislav Kinsbursky 	INIT_LIST_HEAD(&pipe->pipe);
549ba9e0975SStanislav Kinsbursky 	pipe->pipelen = 0;
550ba9e0975SStanislav Kinsbursky 	INIT_DELAYED_WORK(&pipe->queue_timeout,
551ba9e0975SStanislav Kinsbursky 			    rpc_timeout_upcall_queue);
552ba9e0975SStanislav Kinsbursky 	pipe->ops = NULL;
553ba9e0975SStanislav Kinsbursky 	spin_lock_init(&pipe->lock);
554c239d83bSStanislav Kinsbursky 	pipe->dentry = NULL;
555ba9e0975SStanislav Kinsbursky }
556ba9e0975SStanislav Kinsbursky 
557c239d83bSStanislav Kinsbursky void rpc_destroy_pipe_data(struct rpc_pipe *pipe)
558c239d83bSStanislav Kinsbursky {
559c239d83bSStanislav Kinsbursky 	kfree(pipe);
560c239d83bSStanislav Kinsbursky }
561c239d83bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_destroy_pipe_data);
562c239d83bSStanislav Kinsbursky 
563c239d83bSStanislav Kinsbursky struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags)
5647589806eSTrond Myklebust {
565ba9e0975SStanislav Kinsbursky 	struct rpc_pipe *pipe;
5667589806eSTrond Myklebust 
567ba9e0975SStanislav Kinsbursky 	pipe = kzalloc(sizeof(struct rpc_pipe), GFP_KERNEL);
568ba9e0975SStanislav Kinsbursky 	if (!pipe)
569c239d83bSStanislav Kinsbursky 		return ERR_PTR(-ENOMEM);
570ba9e0975SStanislav Kinsbursky 	init_pipe(pipe);
571c239d83bSStanislav Kinsbursky 	pipe->ops = ops;
572c239d83bSStanislav Kinsbursky 	pipe->flags = flags;
573c239d83bSStanislav Kinsbursky 	return pipe;
574ba9e0975SStanislav Kinsbursky }
575c239d83bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_mkpipe_data);
576c239d83bSStanislav Kinsbursky 
577c239d83bSStanislav Kinsbursky static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
5787589806eSTrond Myklebust 			       umode_t mode,
5797589806eSTrond Myklebust 			       const struct file_operations *i_fop,
5807589806eSTrond Myklebust 			       void *private,
581c239d83bSStanislav Kinsbursky 			       struct rpc_pipe *pipe)
5827589806eSTrond Myklebust {
5837589806eSTrond Myklebust 	struct rpc_inode *rpci;
5847589806eSTrond Myklebust 	int err;
5857589806eSTrond Myklebust 
5867589806eSTrond Myklebust 	err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private);
5877589806eSTrond Myklebust 	if (err)
5887589806eSTrond Myklebust 		return err;
589c5ef6035SDavid Howells 	rpci = RPC_I(d_inode(dentry));
5907589806eSTrond Myklebust 	rpci->private = private;
591ba9e0975SStanislav Kinsbursky 	rpci->pipe = pipe;
5927589806eSTrond Myklebust 	fsnotify_create(dir, dentry);
5937589806eSTrond Myklebust 	return 0;
5947589806eSTrond Myklebust }
5957589806eSTrond Myklebust 
596ac6feceeSTrond Myklebust static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
597ac6feceeSTrond Myklebust {
598ac6feceeSTrond Myklebust 	int ret;
599ac6feceeSTrond Myklebust 
600ac6feceeSTrond Myklebust 	dget(dentry);
601ac6feceeSTrond Myklebust 	ret = simple_rmdir(dir, dentry);
602a35d632cSAmir Goldstein 	if (!ret)
603a35d632cSAmir Goldstein 		fsnotify_rmdir(dir, dentry);
604ac6feceeSTrond Myklebust 	d_delete(dentry);
605ac6feceeSTrond Myklebust 	dput(dentry);
606ac6feceeSTrond Myklebust 	return ret;
607ac6feceeSTrond Myklebust }
608ac6feceeSTrond Myklebust 
609810d90bcSTrond Myklebust static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
610810d90bcSTrond Myklebust {
611810d90bcSTrond Myklebust 	int ret;
612810d90bcSTrond Myklebust 
613810d90bcSTrond Myklebust 	dget(dentry);
614810d90bcSTrond Myklebust 	ret = simple_unlink(dir, dentry);
615a35d632cSAmir Goldstein 	if (!ret)
616a35d632cSAmir Goldstein 		fsnotify_unlink(dir, dentry);
617810d90bcSTrond Myklebust 	d_delete(dentry);
618810d90bcSTrond Myklebust 	dput(dentry);
619810d90bcSTrond Myklebust 	return ret;
620810d90bcSTrond Myklebust }
621810d90bcSTrond Myklebust 
622810d90bcSTrond Myklebust static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry)
623810d90bcSTrond Myklebust {
624c5ef6035SDavid Howells 	struct inode *inode = d_inode(dentry);
625810d90bcSTrond Myklebust 
626810d90bcSTrond Myklebust 	rpc_close_pipes(inode);
627810d90bcSTrond Myklebust 	return __rpc_unlink(dir, dentry);
628810d90bcSTrond Myklebust }
629810d90bcSTrond Myklebust 
630cfeaa4a3STrond Myklebust static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
631d3db90b0SAl Viro 					  const char *name)
632cfeaa4a3STrond Myklebust {
633d3db90b0SAl Viro 	struct qstr q = QSTR_INIT(name, strlen(name));
634d3db90b0SAl Viro 	struct dentry *dentry = d_hash_and_lookup(parent, &q);
6355bff0386SStanislav Kinsbursky 	if (!dentry) {
636d3db90b0SAl Viro 		dentry = d_alloc(parent, &q);
6375bff0386SStanislav Kinsbursky 		if (!dentry)
6385bff0386SStanislav Kinsbursky 			return ERR_PTR(-ENOMEM);
6395bff0386SStanislav Kinsbursky 	}
640c5ef6035SDavid Howells 	if (d_really_is_negative(dentry))
641f1f0abe1SDan Carpenter 		return dentry;
642cfeaa4a3STrond Myklebust 	dput(dentry);
643cfeaa4a3STrond Myklebust 	return ERR_PTR(-EEXIST);
644cfeaa4a3STrond Myklebust }
645cfeaa4a3STrond Myklebust 
6461da177e4SLinus Torvalds /*
6471da177e4SLinus Torvalds  * FIXME: This probably has races.
6481da177e4SLinus Torvalds  */
649ac6feceeSTrond Myklebust static void __rpc_depopulate(struct dentry *parent,
650ac6feceeSTrond Myklebust 			     const struct rpc_filelist *files,
651ac6feceeSTrond Myklebust 			     int start, int eof)
6521da177e4SLinus Torvalds {
653c5ef6035SDavid Howells 	struct inode *dir = d_inode(parent);
654ac6feceeSTrond Myklebust 	struct dentry *dentry;
655ac6feceeSTrond Myklebust 	struct qstr name;
656ac6feceeSTrond Myklebust 	int i;
657ac6feceeSTrond Myklebust 
658ac6feceeSTrond Myklebust 	for (i = start; i < eof; i++) {
659ac6feceeSTrond Myklebust 		name.name = files[i].name;
660ac6feceeSTrond Myklebust 		name.len = strlen(files[i].name);
661d3db90b0SAl Viro 		dentry = d_hash_and_lookup(parent, &name);
662ac6feceeSTrond Myklebust 
663ac6feceeSTrond Myklebust 		if (dentry == NULL)
664ac6feceeSTrond Myklebust 			continue;
665c5ef6035SDavid Howells 		if (d_really_is_negative(dentry))
666ac6feceeSTrond Myklebust 			goto next;
667c5ef6035SDavid Howells 		switch (d_inode(dentry)->i_mode & S_IFMT) {
668ac6feceeSTrond Myklebust 			default:
669ac6feceeSTrond Myklebust 				BUG();
670ac6feceeSTrond Myklebust 			case S_IFREG:
671ac6feceeSTrond Myklebust 				__rpc_unlink(dir, dentry);
672ac6feceeSTrond Myklebust 				break;
673ac6feceeSTrond Myklebust 			case S_IFDIR:
674ac6feceeSTrond Myklebust 				__rpc_rmdir(dir, dentry);
675ac6feceeSTrond Myklebust 		}
676ac6feceeSTrond Myklebust next:
677ac6feceeSTrond Myklebust 		dput(dentry);
678ac6feceeSTrond Myklebust 	}
679ac6feceeSTrond Myklebust }
680ac6feceeSTrond Myklebust 
681ac6feceeSTrond Myklebust static void rpc_depopulate(struct dentry *parent,
682ac6feceeSTrond Myklebust 			   const struct rpc_filelist *files,
683ac6feceeSTrond Myklebust 			   int start, int eof)
684ac6feceeSTrond Myklebust {
685c5ef6035SDavid Howells 	struct inode *dir = d_inode(parent);
6861da177e4SLinus Torvalds 
6875955102cSAl Viro 	inode_lock_nested(dir, I_MUTEX_CHILD);
688ac6feceeSTrond Myklebust 	__rpc_depopulate(parent, files, start, eof);
6895955102cSAl Viro 	inode_unlock(dir);
6901da177e4SLinus Torvalds }
6911da177e4SLinus Torvalds 
692ac6feceeSTrond Myklebust static int rpc_populate(struct dentry *parent,
693ac6feceeSTrond Myklebust 			const struct rpc_filelist *files,
694ac6feceeSTrond Myklebust 			int start, int eof,
695ac6feceeSTrond Myklebust 			void *private)
6961da177e4SLinus Torvalds {
697c5ef6035SDavid Howells 	struct inode *dir = d_inode(parent);
6981da177e4SLinus Torvalds 	struct dentry *dentry;
699ac6feceeSTrond Myklebust 	int i, err;
7001da177e4SLinus Torvalds 
7015955102cSAl Viro 	inode_lock(dir);
7021da177e4SLinus Torvalds 	for (i = start; i < eof; i++) {
703d3db90b0SAl Viro 		dentry = __rpc_lookup_create_exclusive(parent, files[i].name);
704ac6feceeSTrond Myklebust 		err = PTR_ERR(dentry);
705ac6feceeSTrond Myklebust 		if (IS_ERR(dentry))
7061da177e4SLinus Torvalds 			goto out_bad;
707ac6feceeSTrond Myklebust 		switch (files[i].mode & S_IFMT) {
708ac6feceeSTrond Myklebust 			default:
709ac6feceeSTrond Myklebust 				BUG();
710ac6feceeSTrond Myklebust 			case S_IFREG:
711ac6feceeSTrond Myklebust 				err = __rpc_create(dir, dentry,
712ac6feceeSTrond Myklebust 						files[i].mode,
713ac6feceeSTrond Myklebust 						files[i].i_fop,
714ac6feceeSTrond Myklebust 						private);
715ac6feceeSTrond Myklebust 				break;
716ac6feceeSTrond Myklebust 			case S_IFDIR:
717ac6feceeSTrond Myklebust 				err = __rpc_mkdir(dir, dentry,
718ac6feceeSTrond Myklebust 						files[i].mode,
719ac6feceeSTrond Myklebust 						NULL,
720ac6feceeSTrond Myklebust 						private);
7211da177e4SLinus Torvalds 		}
722ac6feceeSTrond Myklebust 		if (err != 0)
723ac6feceeSTrond Myklebust 			goto out_bad;
7241da177e4SLinus Torvalds 	}
7255955102cSAl Viro 	inode_unlock(dir);
7261da177e4SLinus Torvalds 	return 0;
7271da177e4SLinus Torvalds out_bad:
728ac6feceeSTrond Myklebust 	__rpc_depopulate(parent, files, start, eof);
7295955102cSAl Viro 	inode_unlock(dir);
7301e903edaSAl Viro 	printk(KERN_WARNING "%s: %s failed to populate directory %pd\n",
7311e903edaSAl Viro 			__FILE__, __func__, parent);
732ac6feceeSTrond Myklebust 	return err;
733f134585aSTrond Myklebust }
734f134585aSTrond Myklebust 
735e57aed77STrond Myklebust static struct dentry *rpc_mkdir_populate(struct dentry *parent,
736a95e691fSAl Viro 		const char *name, umode_t mode, void *private,
737e57aed77STrond Myklebust 		int (*populate)(struct dentry *, void *), void *args_populate)
738f134585aSTrond Myklebust {
739f134585aSTrond Myklebust 	struct dentry *dentry;
740c5ef6035SDavid Howells 	struct inode *dir = d_inode(parent);
741f134585aSTrond Myklebust 	int error;
742f134585aSTrond Myklebust 
7435955102cSAl Viro 	inode_lock_nested(dir, I_MUTEX_PARENT);
7447d59d1e8STrond Myklebust 	dentry = __rpc_lookup_create_exclusive(parent, name);
745f134585aSTrond Myklebust 	if (IS_ERR(dentry))
7467d59d1e8STrond Myklebust 		goto out;
7477d59d1e8STrond Myklebust 	error = __rpc_mkdir(dir, dentry, mode, NULL, private);
7487589806eSTrond Myklebust 	if (error != 0)
7497589806eSTrond Myklebust 		goto out_err;
750e57aed77STrond Myklebust 	if (populate != NULL) {
751e57aed77STrond Myklebust 		error = populate(dentry, args_populate);
752f134585aSTrond Myklebust 		if (error)
753ac6feceeSTrond Myklebust 			goto err_rmdir;
754e57aed77STrond Myklebust 	}
755f134585aSTrond Myklebust out:
7565955102cSAl Viro 	inode_unlock(dir);
7575c3e985aSTrond Myklebust 	return dentry;
758ac6feceeSTrond Myklebust err_rmdir:
759f134585aSTrond Myklebust 	__rpc_rmdir(dir, dentry);
7607589806eSTrond Myklebust out_err:
761f134585aSTrond Myklebust 	dentry = ERR_PTR(error);
762f134585aSTrond Myklebust 	goto out;
763f134585aSTrond Myklebust }
764f134585aSTrond Myklebust 
765e57aed77STrond Myklebust static int rpc_rmdir_depopulate(struct dentry *dentry,
766e57aed77STrond Myklebust 		void (*depopulate)(struct dentry *))
767f134585aSTrond Myklebust {
768dff02cc1STrond Myklebust 	struct dentry *parent;
769f134585aSTrond Myklebust 	struct inode *dir;
770f134585aSTrond Myklebust 	int error;
771f134585aSTrond Myklebust 
772dff02cc1STrond Myklebust 	parent = dget_parent(dentry);
773c5ef6035SDavid Howells 	dir = d_inode(parent);
7745955102cSAl Viro 	inode_lock_nested(dir, I_MUTEX_PARENT);
775e57aed77STrond Myklebust 	if (depopulate != NULL)
776e57aed77STrond Myklebust 		depopulate(dentry);
777f134585aSTrond Myklebust 	error = __rpc_rmdir(dir, dentry);
7785955102cSAl Viro 	inode_unlock(dir);
779dff02cc1STrond Myklebust 	dput(parent);
780f134585aSTrond Myklebust 	return error;
781f134585aSTrond Myklebust }
7821da177e4SLinus Torvalds 
78393a44a75SJ. Bruce Fields /**
78493a44a75SJ. Bruce Fields  * rpc_mkpipe - make an rpc_pipefs file for kernel<->userspace communication
78593a44a75SJ. Bruce Fields  * @parent: dentry of directory to create new "pipe" in
78693a44a75SJ. Bruce Fields  * @name: name of pipe
78793a44a75SJ. Bruce Fields  * @private: private data to associate with the pipe, for the caller's use
788bda14606SRandy Dunlap  * @pipe: &rpc_pipe containing input parameters
78993a44a75SJ. Bruce Fields  *
79093a44a75SJ. Bruce Fields  * Data is made available for userspace to read by calls to
79193a44a75SJ. Bruce Fields  * rpc_queue_upcall().  The actual reads will result in calls to
79293a44a75SJ. Bruce Fields  * @ops->upcall, which will be called with the file pointer,
79393a44a75SJ. Bruce Fields  * message, and userspace buffer to copy to.
79493a44a75SJ. Bruce Fields  *
79593a44a75SJ. Bruce Fields  * Writes can come at any time, and do not necessarily have to be
79693a44a75SJ. Bruce Fields  * responses to upcalls.  They will result in calls to @msg->downcall.
79793a44a75SJ. Bruce Fields  *
79893a44a75SJ. Bruce Fields  * The @private argument passed here will be available to all these methods
799496ad9aaSAl Viro  * from the file pointer, via RPC_I(file_inode(file))->private.
80093a44a75SJ. Bruce Fields  */
801c239d83bSStanislav Kinsbursky struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name,
802c239d83bSStanislav Kinsbursky 				 void *private, struct rpc_pipe *pipe)
8031da177e4SLinus Torvalds {
8041da177e4SLinus Torvalds 	struct dentry *dentry;
805c5ef6035SDavid Howells 	struct inode *dir = d_inode(parent);
806d6444062SJoe Perches 	umode_t umode = S_IFIFO | 0600;
8077589806eSTrond Myklebust 	int err;
8087364af6aSTrond Myklebust 
809c239d83bSStanislav Kinsbursky 	if (pipe->ops->upcall == NULL)
810d6444062SJoe Perches 		umode &= ~0444;
811c239d83bSStanislav Kinsbursky 	if (pipe->ops->downcall == NULL)
812d6444062SJoe Perches 		umode &= ~0222;
8131da177e4SLinus Torvalds 
8145955102cSAl Viro 	inode_lock_nested(dir, I_MUTEX_PARENT);
815d3db90b0SAl Viro 	dentry = __rpc_lookup_create_exclusive(parent, name);
8161da177e4SLinus Torvalds 	if (IS_ERR(dentry))
817cfeaa4a3STrond Myklebust 		goto out;
818c239d83bSStanislav Kinsbursky 	err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops,
819c239d83bSStanislav Kinsbursky 				  private, pipe);
8207589806eSTrond Myklebust 	if (err)
8217589806eSTrond Myklebust 		goto out_err;
822f134585aSTrond Myklebust out:
8235955102cSAl Viro 	inode_unlock(dir);
8245c3e985aSTrond Myklebust 	return dentry;
8257589806eSTrond Myklebust out_err:
8267589806eSTrond Myklebust 	dentry = ERR_PTR(err);
8271e903edaSAl Viro 	printk(KERN_WARNING "%s: %s() failed to create pipe %pd/%s (errno = %d)\n",
8281e903edaSAl Viro 			__FILE__, __func__, parent, name,
8297589806eSTrond Myklebust 			err);
830f134585aSTrond Myklebust 	goto out;
8311da177e4SLinus Torvalds }
832c239d83bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry);
8331da177e4SLinus Torvalds 
83493a44a75SJ. Bruce Fields /**
83593a44a75SJ. Bruce Fields  * rpc_unlink - remove a pipe
83693a44a75SJ. Bruce Fields  * @dentry: dentry for the pipe, as returned from rpc_mkpipe
83793a44a75SJ. Bruce Fields  *
83893a44a75SJ. Bruce Fields  * After this call, lookups will no longer find the pipe, and any
83993a44a75SJ. Bruce Fields  * attempts to read or write using preexisting opens of the pipe will
84093a44a75SJ. Bruce Fields  * return -EPIPE.
84193a44a75SJ. Bruce Fields  */
842f134585aSTrond Myklebust int
8435d67476fSTrond Myklebust rpc_unlink(struct dentry *dentry)
8441da177e4SLinus Torvalds {
8455d67476fSTrond Myklebust 	struct dentry *parent;
846f134585aSTrond Myklebust 	struct inode *dir;
8475d67476fSTrond Myklebust 	int error = 0;
8481da177e4SLinus Torvalds 
8495d67476fSTrond Myklebust 	parent = dget_parent(dentry);
850c5ef6035SDavid Howells 	dir = d_inode(parent);
8515955102cSAl Viro 	inode_lock_nested(dir, I_MUTEX_PARENT);
852810d90bcSTrond Myklebust 	error = __rpc_rmpipe(dir, dentry);
8535955102cSAl Viro 	inode_unlock(dir);
8545d67476fSTrond Myklebust 	dput(parent);
855f134585aSTrond Myklebust 	return error;
8561da177e4SLinus Torvalds }
857468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_unlink);
8581da177e4SLinus Torvalds 
8596739ffb7STrond Myklebust /**
8606739ffb7STrond Myklebust  * rpc_init_pipe_dir_head - initialise a struct rpc_pipe_dir_head
8616739ffb7STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
8626739ffb7STrond Myklebust  */
8636739ffb7STrond Myklebust void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh)
8646739ffb7STrond Myklebust {
8656739ffb7STrond Myklebust 	INIT_LIST_HEAD(&pdh->pdh_entries);
8666739ffb7STrond Myklebust 	pdh->pdh_dentry = NULL;
8676739ffb7STrond Myklebust }
8686739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_head);
8696739ffb7STrond Myklebust 
8706739ffb7STrond Myklebust /**
8716739ffb7STrond Myklebust  * rpc_init_pipe_dir_object - initialise a struct rpc_pipe_dir_object
8726739ffb7STrond Myklebust  * @pdo: pointer to struct rpc_pipe_dir_object
8736739ffb7STrond Myklebust  * @pdo_ops: pointer to const struct rpc_pipe_dir_object_ops
8746739ffb7STrond Myklebust  * @pdo_data: pointer to caller-defined data
8756739ffb7STrond Myklebust  */
8766739ffb7STrond Myklebust void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo,
8776739ffb7STrond Myklebust 		const struct rpc_pipe_dir_object_ops *pdo_ops,
8786739ffb7STrond Myklebust 		void *pdo_data)
8796739ffb7STrond Myklebust {
8806739ffb7STrond Myklebust 	INIT_LIST_HEAD(&pdo->pdo_head);
8816739ffb7STrond Myklebust 	pdo->pdo_ops = pdo_ops;
8826739ffb7STrond Myklebust 	pdo->pdo_data = pdo_data;
8836739ffb7STrond Myklebust }
8846739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_object);
8856739ffb7STrond Myklebust 
8866739ffb7STrond Myklebust static int
8876739ffb7STrond Myklebust rpc_add_pipe_dir_object_locked(struct net *net,
8886739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
8896739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
8906739ffb7STrond Myklebust {
8916739ffb7STrond Myklebust 	int ret = 0;
8926739ffb7STrond Myklebust 
8936739ffb7STrond Myklebust 	if (pdh->pdh_dentry)
8946739ffb7STrond Myklebust 		ret = pdo->pdo_ops->create(pdh->pdh_dentry, pdo);
8956739ffb7STrond Myklebust 	if (ret == 0)
8966739ffb7STrond Myklebust 		list_add_tail(&pdo->pdo_head, &pdh->pdh_entries);
8976739ffb7STrond Myklebust 	return ret;
8986739ffb7STrond Myklebust }
8996739ffb7STrond Myklebust 
9006739ffb7STrond Myklebust static void
9016739ffb7STrond Myklebust rpc_remove_pipe_dir_object_locked(struct net *net,
9026739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
9036739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
9046739ffb7STrond Myklebust {
9056739ffb7STrond Myklebust 	if (pdh->pdh_dentry)
9066739ffb7STrond Myklebust 		pdo->pdo_ops->destroy(pdh->pdh_dentry, pdo);
9076739ffb7STrond Myklebust 	list_del_init(&pdo->pdo_head);
9086739ffb7STrond Myklebust }
9096739ffb7STrond Myklebust 
9106739ffb7STrond Myklebust /**
9116739ffb7STrond Myklebust  * rpc_add_pipe_dir_object - associate a rpc_pipe_dir_object to a directory
9126739ffb7STrond Myklebust  * @net: pointer to struct net
9136739ffb7STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
9146739ffb7STrond Myklebust  * @pdo: pointer to struct rpc_pipe_dir_object
9156739ffb7STrond Myklebust  *
9166739ffb7STrond Myklebust  */
9176739ffb7STrond Myklebust int
9186739ffb7STrond Myklebust rpc_add_pipe_dir_object(struct net *net,
9196739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
9206739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
9216739ffb7STrond Myklebust {
9226739ffb7STrond Myklebust 	int ret = 0;
9236739ffb7STrond Myklebust 
9246739ffb7STrond Myklebust 	if (list_empty(&pdo->pdo_head)) {
9256739ffb7STrond Myklebust 		struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
9266739ffb7STrond Myklebust 
9276739ffb7STrond Myklebust 		mutex_lock(&sn->pipefs_sb_lock);
9286739ffb7STrond Myklebust 		ret = rpc_add_pipe_dir_object_locked(net, pdh, pdo);
9296739ffb7STrond Myklebust 		mutex_unlock(&sn->pipefs_sb_lock);
9306739ffb7STrond Myklebust 	}
9316739ffb7STrond Myklebust 	return ret;
9326739ffb7STrond Myklebust }
9336739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_add_pipe_dir_object);
9346739ffb7STrond Myklebust 
9356739ffb7STrond Myklebust /**
9366739ffb7STrond Myklebust  * rpc_remove_pipe_dir_object - remove a rpc_pipe_dir_object from a directory
9376739ffb7STrond Myklebust  * @net: pointer to struct net
9386739ffb7STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
9396739ffb7STrond Myklebust  * @pdo: pointer to struct rpc_pipe_dir_object
9406739ffb7STrond Myklebust  *
9416739ffb7STrond Myklebust  */
9426739ffb7STrond Myklebust void
9436739ffb7STrond Myklebust rpc_remove_pipe_dir_object(struct net *net,
9446739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
9456739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
9466739ffb7STrond Myklebust {
9476739ffb7STrond Myklebust 	if (!list_empty(&pdo->pdo_head)) {
9486739ffb7STrond Myklebust 		struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
9496739ffb7STrond Myklebust 
9506739ffb7STrond Myklebust 		mutex_lock(&sn->pipefs_sb_lock);
9516739ffb7STrond Myklebust 		rpc_remove_pipe_dir_object_locked(net, pdh, pdo);
9526739ffb7STrond Myklebust 		mutex_unlock(&sn->pipefs_sb_lock);
9536739ffb7STrond Myklebust 	}
9546739ffb7STrond Myklebust }
9556739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_remove_pipe_dir_object);
9566739ffb7STrond Myklebust 
957298fc355STrond Myklebust /**
958298fc355STrond Myklebust  * rpc_find_or_alloc_pipe_dir_object
959298fc355STrond Myklebust  * @net: pointer to struct net
960298fc355STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
961298fc355STrond Myklebust  * @match: match struct rpc_pipe_dir_object to data
962298fc355STrond Myklebust  * @alloc: allocate a new struct rpc_pipe_dir_object
963298fc355STrond Myklebust  * @data: user defined data for match() and alloc()
964298fc355STrond Myklebust  *
965298fc355STrond Myklebust  */
966298fc355STrond Myklebust struct rpc_pipe_dir_object *
967298fc355STrond Myklebust rpc_find_or_alloc_pipe_dir_object(struct net *net,
968298fc355STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
969298fc355STrond Myklebust 		int (*match)(struct rpc_pipe_dir_object *, void *),
970298fc355STrond Myklebust 		struct rpc_pipe_dir_object *(*alloc)(void *),
971298fc355STrond Myklebust 		void *data)
972298fc355STrond Myklebust {
973298fc355STrond Myklebust 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
974298fc355STrond Myklebust 	struct rpc_pipe_dir_object *pdo;
975298fc355STrond Myklebust 
976298fc355STrond Myklebust 	mutex_lock(&sn->pipefs_sb_lock);
977298fc355STrond Myklebust 	list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) {
978298fc355STrond Myklebust 		if (!match(pdo, data))
979298fc355STrond Myklebust 			continue;
980298fc355STrond Myklebust 		goto out;
981298fc355STrond Myklebust 	}
982298fc355STrond Myklebust 	pdo = alloc(data);
983298fc355STrond Myklebust 	if (!pdo)
984298fc355STrond Myklebust 		goto out;
985298fc355STrond Myklebust 	rpc_add_pipe_dir_object_locked(net, pdh, pdo);
986298fc355STrond Myklebust out:
987298fc355STrond Myklebust 	mutex_unlock(&sn->pipefs_sb_lock);
988298fc355STrond Myklebust 	return pdo;
989298fc355STrond Myklebust }
990298fc355STrond Myklebust EXPORT_SYMBOL_GPL(rpc_find_or_alloc_pipe_dir_object);
991298fc355STrond Myklebust 
9926739ffb7STrond Myklebust static void
9936739ffb7STrond Myklebust rpc_create_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
9946739ffb7STrond Myklebust {
9956739ffb7STrond Myklebust 	struct rpc_pipe_dir_object *pdo;
9966739ffb7STrond Myklebust 	struct dentry *dir = pdh->pdh_dentry;
9976739ffb7STrond Myklebust 
9986739ffb7STrond Myklebust 	list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head)
9996739ffb7STrond Myklebust 		pdo->pdo_ops->create(dir, pdo);
10006739ffb7STrond Myklebust }
10016739ffb7STrond Myklebust 
10026739ffb7STrond Myklebust static void
10036739ffb7STrond Myklebust rpc_destroy_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
10046739ffb7STrond Myklebust {
10056739ffb7STrond Myklebust 	struct rpc_pipe_dir_object *pdo;
10066739ffb7STrond Myklebust 	struct dentry *dir = pdh->pdh_dentry;
10076739ffb7STrond Myklebust 
10086739ffb7STrond Myklebust 	list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head)
10096739ffb7STrond Myklebust 		pdo->pdo_ops->destroy(dir, pdo);
10106739ffb7STrond Myklebust }
10116739ffb7STrond Myklebust 
1012e57aed77STrond Myklebust enum {
1013e57aed77STrond Myklebust 	RPCAUTH_info,
1014e57aed77STrond Myklebust 	RPCAUTH_EOF
1015e57aed77STrond Myklebust };
1016e57aed77STrond Myklebust 
1017e57aed77STrond Myklebust static const struct rpc_filelist authfiles[] = {
1018e57aed77STrond Myklebust 	[RPCAUTH_info] = {
1019e57aed77STrond Myklebust 		.name = "info",
1020e57aed77STrond Myklebust 		.i_fop = &rpc_info_operations,
1021d6444062SJoe Perches 		.mode = S_IFREG | 0400,
1022e57aed77STrond Myklebust 	},
1023e57aed77STrond Myklebust };
1024e57aed77STrond Myklebust 
1025e57aed77STrond Myklebust static int rpc_clntdir_populate(struct dentry *dentry, void *private)
1026e57aed77STrond Myklebust {
1027e57aed77STrond Myklebust 	return rpc_populate(dentry,
1028e57aed77STrond Myklebust 			    authfiles, RPCAUTH_info, RPCAUTH_EOF,
1029e57aed77STrond Myklebust 			    private);
1030e57aed77STrond Myklebust }
1031e57aed77STrond Myklebust 
1032e57aed77STrond Myklebust static void rpc_clntdir_depopulate(struct dentry *dentry)
1033e57aed77STrond Myklebust {
1034e57aed77STrond Myklebust 	rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF);
1035e57aed77STrond Myklebust }
1036e57aed77STrond Myklebust 
10377d59d1e8STrond Myklebust /**
10387d59d1e8STrond Myklebust  * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs
1039a95e691fSAl Viro  * @dentry: the parent of new directory
1040a95e691fSAl Viro  * @name: the name of new directory
10417d59d1e8STrond Myklebust  * @rpc_client: rpc client to associate with this directory
10427d59d1e8STrond Myklebust  *
10437d59d1e8STrond Myklebust  * This creates a directory at the given @path associated with
10447d59d1e8STrond Myklebust  * @rpc_clnt, which will contain a file named "info" with some basic
10457d59d1e8STrond Myklebust  * information about the client, together with any "pipes" that may
10467d59d1e8STrond Myklebust  * later be created using rpc_mkpipe().
10477d59d1e8STrond Myklebust  */
104823ac6581STrond Myklebust struct dentry *rpc_create_client_dir(struct dentry *dentry,
1049a95e691fSAl Viro 				   const char *name,
10507d59d1e8STrond Myklebust 				   struct rpc_clnt *rpc_client)
10517d59d1e8STrond Myklebust {
10526739ffb7STrond Myklebust 	struct dentry *ret;
10536739ffb7STrond Myklebust 
1054d6444062SJoe Perches 	ret = rpc_mkdir_populate(dentry, name, 0555, NULL,
1055e57aed77STrond Myklebust 				 rpc_clntdir_populate, rpc_client);
10566739ffb7STrond Myklebust 	if (!IS_ERR(ret)) {
10576739ffb7STrond Myklebust 		rpc_client->cl_pipedir_objects.pdh_dentry = ret;
10586739ffb7STrond Myklebust 		rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
10596739ffb7STrond Myklebust 	}
10606739ffb7STrond Myklebust 	return ret;
1061e57aed77STrond Myklebust }
1062e57aed77STrond Myklebust 
1063e57aed77STrond Myklebust /**
1064e57aed77STrond Myklebust  * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
10656739ffb7STrond Myklebust  * @rpc_client: rpc_client for the pipe
1066e57aed77STrond Myklebust  */
1067c36dcfe1STrond Myklebust int rpc_remove_client_dir(struct rpc_clnt *rpc_client)
1068e57aed77STrond Myklebust {
1069c36dcfe1STrond Myklebust 	struct dentry *dentry = rpc_client->cl_pipedir_objects.pdh_dentry;
1070c36dcfe1STrond Myklebust 
1071c36dcfe1STrond Myklebust 	if (dentry == NULL)
1072c36dcfe1STrond Myklebust 		return 0;
10736739ffb7STrond Myklebust 	rpc_destroy_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
10746739ffb7STrond Myklebust 	rpc_client->cl_pipedir_objects.pdh_dentry = NULL;
1075e57aed77STrond Myklebust 	return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate);
10767d59d1e8STrond Myklebust }
10777d59d1e8STrond Myklebust 
10788854e82dSTrond Myklebust static const struct rpc_filelist cache_pipefs_files[3] = {
10798854e82dSTrond Myklebust 	[0] = {
10808854e82dSTrond Myklebust 		.name = "channel",
10818854e82dSTrond Myklebust 		.i_fop = &cache_file_operations_pipefs,
1082d6444062SJoe Perches 		.mode = S_IFREG | 0600,
10838854e82dSTrond Myklebust 	},
10848854e82dSTrond Myklebust 	[1] = {
10858854e82dSTrond Myklebust 		.name = "content",
10868854e82dSTrond Myklebust 		.i_fop = &content_file_operations_pipefs,
1087d6444062SJoe Perches 		.mode = S_IFREG | 0400,
10888854e82dSTrond Myklebust 	},
10898854e82dSTrond Myklebust 	[2] = {
10908854e82dSTrond Myklebust 		.name = "flush",
10918854e82dSTrond Myklebust 		.i_fop = &cache_flush_operations_pipefs,
1092d6444062SJoe Perches 		.mode = S_IFREG | 0600,
10938854e82dSTrond Myklebust 	},
10948854e82dSTrond Myklebust };
10958854e82dSTrond Myklebust 
10968854e82dSTrond Myklebust static int rpc_cachedir_populate(struct dentry *dentry, void *private)
10978854e82dSTrond Myklebust {
10988854e82dSTrond Myklebust 	return rpc_populate(dentry,
10998854e82dSTrond Myklebust 			    cache_pipefs_files, 0, 3,
11008854e82dSTrond Myklebust 			    private);
11018854e82dSTrond Myklebust }
11028854e82dSTrond Myklebust 
11038854e82dSTrond Myklebust static void rpc_cachedir_depopulate(struct dentry *dentry)
11048854e82dSTrond Myklebust {
11058854e82dSTrond Myklebust 	rpc_depopulate(dentry, cache_pipefs_files, 0, 3);
11068854e82dSTrond Myklebust }
11078854e82dSTrond Myklebust 
1108a95e691fSAl Viro struct dentry *rpc_create_cache_dir(struct dentry *parent, const char *name,
110964f1426fSAl Viro 				    umode_t umode, struct cache_detail *cd)
11108854e82dSTrond Myklebust {
11118854e82dSTrond Myklebust 	return rpc_mkdir_populate(parent, name, umode, NULL,
11128854e82dSTrond Myklebust 			rpc_cachedir_populate, cd);
11138854e82dSTrond Myklebust }
11148854e82dSTrond Myklebust 
11158854e82dSTrond Myklebust void rpc_remove_cache_dir(struct dentry *dentry)
11168854e82dSTrond Myklebust {
11178854e82dSTrond Myklebust 	rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate);
11188854e82dSTrond Myklebust }
11198854e82dSTrond Myklebust 
11201da177e4SLinus Torvalds /*
11211da177e4SLinus Torvalds  * populate the filesystem
11221da177e4SLinus Torvalds  */
1123b87221deSAlexey Dobriyan static const struct super_operations s_ops = {
11241da177e4SLinus Torvalds 	.alloc_inode	= rpc_alloc_inode,
1125bef252faSAl Viro 	.free_inode	= rpc_free_inode,
11261da177e4SLinus Torvalds 	.statfs		= simple_statfs,
11271da177e4SLinus Torvalds };
11281da177e4SLinus Torvalds 
11291da177e4SLinus Torvalds #define RPCAUTH_GSSMAGIC 0x67596969
11301da177e4SLinus Torvalds 
1131bb156749STrond Myklebust /*
1132bb156749STrond Myklebust  * We have a single directory with 1 node in it.
1133bb156749STrond Myklebust  */
1134bb156749STrond Myklebust enum {
1135bb156749STrond Myklebust 	RPCAUTH_lockd,
1136bb156749STrond Myklebust 	RPCAUTH_mount,
1137bb156749STrond Myklebust 	RPCAUTH_nfs,
1138bb156749STrond Myklebust 	RPCAUTH_portmap,
1139bb156749STrond Myklebust 	RPCAUTH_statd,
1140bb156749STrond Myklebust 	RPCAUTH_nfsd4_cb,
1141e571cbf1STrond Myklebust 	RPCAUTH_cache,
1142b3537c35SJeff Layton 	RPCAUTH_nfsd,
11434b9a445eSJeff Layton 	RPCAUTH_gssd,
1144bb156749STrond Myklebust 	RPCAUTH_RootEOF
1145bb156749STrond Myklebust };
1146bb156749STrond Myklebust 
1147bb156749STrond Myklebust static const struct rpc_filelist files[] = {
1148bb156749STrond Myklebust 	[RPCAUTH_lockd] = {
1149bb156749STrond Myklebust 		.name = "lockd",
1150d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1151bb156749STrond Myklebust 	},
1152bb156749STrond Myklebust 	[RPCAUTH_mount] = {
1153bb156749STrond Myklebust 		.name = "mount",
1154d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1155bb156749STrond Myklebust 	},
1156bb156749STrond Myklebust 	[RPCAUTH_nfs] = {
1157bb156749STrond Myklebust 		.name = "nfs",
1158d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1159bb156749STrond Myklebust 	},
1160bb156749STrond Myklebust 	[RPCAUTH_portmap] = {
1161bb156749STrond Myklebust 		.name = "portmap",
1162d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1163bb156749STrond Myklebust 	},
1164bb156749STrond Myklebust 	[RPCAUTH_statd] = {
1165bb156749STrond Myklebust 		.name = "statd",
1166d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1167bb156749STrond Myklebust 	},
1168bb156749STrond Myklebust 	[RPCAUTH_nfsd4_cb] = {
1169bb156749STrond Myklebust 		.name = "nfsd4_cb",
1170d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1171bb156749STrond Myklebust 	},
1172e571cbf1STrond Myklebust 	[RPCAUTH_cache] = {
1173e571cbf1STrond Myklebust 		.name = "cache",
1174d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1175e571cbf1STrond Myklebust 	},
1176b3537c35SJeff Layton 	[RPCAUTH_nfsd] = {
1177b3537c35SJeff Layton 		.name = "nfsd",
1178d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1179b3537c35SJeff Layton 	},
11804b9a445eSJeff Layton 	[RPCAUTH_gssd] = {
11814b9a445eSJeff Layton 		.name = "gssd",
1182d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
11834b9a445eSJeff Layton 	},
1184bb156749STrond Myklebust };
1185bb156749STrond Myklebust 
1186432eb1a5SStanislav Kinsbursky /*
1187432eb1a5SStanislav Kinsbursky  * This call can be used only in RPC pipefs mount notification hooks.
1188432eb1a5SStanislav Kinsbursky  */
1189432eb1a5SStanislav Kinsbursky struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
1190432eb1a5SStanislav Kinsbursky 			       const unsigned char *dir_name)
1191432eb1a5SStanislav Kinsbursky {
119226fe5750SLinus Torvalds 	struct qstr dir = QSTR_INIT(dir_name, strlen(dir_name));
1193d3db90b0SAl Viro 	return d_hash_and_lookup(sb->s_root, &dir);
1194432eb1a5SStanislav Kinsbursky }
1195432eb1a5SStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
1196432eb1a5SStanislav Kinsbursky 
11974b9a445eSJeff Layton int rpc_pipefs_init_net(struct net *net)
1198c21a588fSStanislav Kinsbursky {
1199c21a588fSStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1200c21a588fSStanislav Kinsbursky 
12014b9a445eSJeff Layton 	sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0);
12024b9a445eSJeff Layton 	if (IS_ERR(sn->gssd_dummy))
12034b9a445eSJeff Layton 		return PTR_ERR(sn->gssd_dummy);
12044b9a445eSJeff Layton 
1205c21a588fSStanislav Kinsbursky 	mutex_init(&sn->pipefs_sb_lock);
12062aed8b47STrond Myklebust 	sn->pipe_version = -1;
12074b9a445eSJeff Layton 	return 0;
12084b9a445eSJeff Layton }
12094b9a445eSJeff Layton 
12104b9a445eSJeff Layton void rpc_pipefs_exit_net(struct net *net)
12114b9a445eSJeff Layton {
12124b9a445eSJeff Layton 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
12134b9a445eSJeff Layton 
12144b9a445eSJeff Layton 	rpc_destroy_pipe_data(sn->gssd_dummy);
1215c21a588fSStanislav Kinsbursky }
1216c21a588fSStanislav Kinsbursky 
1217c21a588fSStanislav Kinsbursky /*
1218c21a588fSStanislav Kinsbursky  * This call will be used for per network namespace operations calls.
1219c21a588fSStanislav Kinsbursky  * Note: Function will be returned with pipefs_sb_lock taken if superblock was
1220c21a588fSStanislav Kinsbursky  * found. This lock have to be released by rpc_put_sb_net() when all operations
1221c21a588fSStanislav Kinsbursky  * will be completed.
1222c21a588fSStanislav Kinsbursky  */
1223c21a588fSStanislav Kinsbursky struct super_block *rpc_get_sb_net(const struct net *net)
1224c21a588fSStanislav Kinsbursky {
1225c21a588fSStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1226c21a588fSStanislav Kinsbursky 
1227c21a588fSStanislav Kinsbursky 	mutex_lock(&sn->pipefs_sb_lock);
1228c21a588fSStanislav Kinsbursky 	if (sn->pipefs_sb)
1229c21a588fSStanislav Kinsbursky 		return sn->pipefs_sb;
1230c21a588fSStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1231c21a588fSStanislav Kinsbursky 	return NULL;
1232c21a588fSStanislav Kinsbursky }
1233c21a588fSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_get_sb_net);
1234c21a588fSStanislav Kinsbursky 
1235c21a588fSStanislav Kinsbursky void rpc_put_sb_net(const struct net *net)
1236c21a588fSStanislav Kinsbursky {
1237c21a588fSStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1238c21a588fSStanislav Kinsbursky 
1239749386e9SWeston Andros Adamson 	WARN_ON(sn->pipefs_sb == NULL);
1240c21a588fSStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1241c21a588fSStanislav Kinsbursky }
1242c21a588fSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_put_sb_net);
1243c21a588fSStanislav Kinsbursky 
12444b9a445eSJeff Layton static const struct rpc_filelist gssd_dummy_clnt_dir[] = {
12454b9a445eSJeff Layton 	[0] = {
12464b9a445eSJeff Layton 		.name = "clntXX",
1247d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
12484b9a445eSJeff Layton 	},
12494b9a445eSJeff Layton };
12504b9a445eSJeff Layton 
12514b9a445eSJeff Layton static ssize_t
12524b9a445eSJeff Layton dummy_downcall(struct file *filp, const char __user *src, size_t len)
12534b9a445eSJeff Layton {
12544b9a445eSJeff Layton 	return -EINVAL;
12554b9a445eSJeff Layton }
12564b9a445eSJeff Layton 
12574b9a445eSJeff Layton static const struct rpc_pipe_ops gssd_dummy_pipe_ops = {
12584b9a445eSJeff Layton 	.upcall		= rpc_pipe_generic_upcall,
12594b9a445eSJeff Layton 	.downcall	= dummy_downcall,
12604b9a445eSJeff Layton };
12614b9a445eSJeff Layton 
1262e2f0c83aSJeff Layton /*
1263e2f0c83aSJeff Layton  * Here we present a bogus "info" file to keep rpc.gssd happy. We don't expect
1264e2f0c83aSJeff Layton  * that it will ever use this info to handle an upcall, but rpc.gssd expects
1265e2f0c83aSJeff Layton  * that this file will be there and have a certain format.
1266e2f0c83aSJeff Layton  */
1267e2f0c83aSJeff Layton static int
1268260f71efSYangtao Li rpc_dummy_info_show(struct seq_file *m, void *v)
1269e2f0c83aSJeff Layton {
1270e2f0c83aSJeff Layton 	seq_printf(m, "RPC server: %s\n", utsname()->nodename);
1271e2f0c83aSJeff Layton 	seq_printf(m, "service: foo (1) version 0\n");
1272e2f0c83aSJeff Layton 	seq_printf(m, "address: 127.0.0.1\n");
1273e2f0c83aSJeff Layton 	seq_printf(m, "protocol: tcp\n");
1274e2f0c83aSJeff Layton 	seq_printf(m, "port: 0\n");
1275e2f0c83aSJeff Layton 	return 0;
1276e2f0c83aSJeff Layton }
1277260f71efSYangtao Li DEFINE_SHOW_ATTRIBUTE(rpc_dummy_info);
1278e2f0c83aSJeff Layton 
1279e2f0c83aSJeff Layton static const struct rpc_filelist gssd_dummy_info_file[] = {
1280e2f0c83aSJeff Layton 	[0] = {
1281e2f0c83aSJeff Layton 		.name = "info",
1282260f71efSYangtao Li 		.i_fop = &rpc_dummy_info_fops,
1283d6444062SJoe Perches 		.mode = S_IFREG | 0400,
1284e2f0c83aSJeff Layton 	},
1285e2f0c83aSJeff Layton };
1286e2f0c83aSJeff Layton 
12874b9a445eSJeff Layton /**
12884b9a445eSJeff Layton  * rpc_gssd_dummy_populate - create a dummy gssd pipe
12894b9a445eSJeff Layton  * @root:	root of the rpc_pipefs filesystem
12904b9a445eSJeff Layton  * @pipe_data:	pipe data created when netns is initialized
12914b9a445eSJeff Layton  *
12924b9a445eSJeff Layton  * Create a dummy set of directories and a pipe that gssd can hold open to
12934b9a445eSJeff Layton  * indicate that it is up and running.
12944b9a445eSJeff Layton  */
12954b9a445eSJeff Layton static struct dentry *
12964b9a445eSJeff Layton rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
12974b9a445eSJeff Layton {
12984b9a445eSJeff Layton 	int ret = 0;
12994b9a445eSJeff Layton 	struct dentry *gssd_dentry;
13004b9a445eSJeff Layton 	struct dentry *clnt_dentry = NULL;
13014b9a445eSJeff Layton 	struct dentry *pipe_dentry = NULL;
13024b9a445eSJeff Layton 	struct qstr q = QSTR_INIT(files[RPCAUTH_gssd].name,
13034b9a445eSJeff Layton 				  strlen(files[RPCAUTH_gssd].name));
13044b9a445eSJeff Layton 
13054b9a445eSJeff Layton 	/* We should never get this far if "gssd" doesn't exist */
13064b9a445eSJeff Layton 	gssd_dentry = d_hash_and_lookup(root, &q);
13074b9a445eSJeff Layton 	if (!gssd_dentry)
13084b9a445eSJeff Layton 		return ERR_PTR(-ENOENT);
13094b9a445eSJeff Layton 
13104b9a445eSJeff Layton 	ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL);
13114b9a445eSJeff Layton 	if (ret) {
13124b9a445eSJeff Layton 		pipe_dentry = ERR_PTR(ret);
13134b9a445eSJeff Layton 		goto out;
13144b9a445eSJeff Layton 	}
13154b9a445eSJeff Layton 
13164b9a445eSJeff Layton 	q.name = gssd_dummy_clnt_dir[0].name;
13174b9a445eSJeff Layton 	q.len = strlen(gssd_dummy_clnt_dir[0].name);
13184b9a445eSJeff Layton 	clnt_dentry = d_hash_and_lookup(gssd_dentry, &q);
13194b9a445eSJeff Layton 	if (!clnt_dentry) {
1320b7ade381SVasily Averin 		__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
13214b9a445eSJeff Layton 		pipe_dentry = ERR_PTR(-ENOENT);
13224b9a445eSJeff Layton 		goto out;
13234b9a445eSJeff Layton 	}
13244b9a445eSJeff Layton 
1325e2f0c83aSJeff Layton 	ret = rpc_populate(clnt_dentry, gssd_dummy_info_file, 0, 1, NULL);
1326e2f0c83aSJeff Layton 	if (ret) {
13273396f92fSJeff Layton 		__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
1328e2f0c83aSJeff Layton 		pipe_dentry = ERR_PTR(ret);
1329e2f0c83aSJeff Layton 		goto out;
1330e2f0c83aSJeff Layton 	}
1331e2f0c83aSJeff Layton 
1332e2f0c83aSJeff Layton 	pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data);
1333e2f0c83aSJeff Layton 	if (IS_ERR(pipe_dentry)) {
1334e2f0c83aSJeff Layton 		__rpc_depopulate(clnt_dentry, gssd_dummy_info_file, 0, 1);
1335e2f0c83aSJeff Layton 		__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
1336e2f0c83aSJeff Layton 	}
13374b9a445eSJeff Layton out:
13384b9a445eSJeff Layton 	dput(clnt_dentry);
13394b9a445eSJeff Layton 	dput(gssd_dentry);
13404b9a445eSJeff Layton 	return pipe_dentry;
13414b9a445eSJeff Layton }
13424b9a445eSJeff Layton 
134323e66ba9SJeff Layton static void
134423e66ba9SJeff Layton rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry)
134523e66ba9SJeff Layton {
134623e66ba9SJeff Layton 	struct dentry *clnt_dir = pipe_dentry->d_parent;
134723e66ba9SJeff Layton 	struct dentry *gssd_dir = clnt_dir->d_parent;
134823e66ba9SJeff Layton 
13494a3877c4SAl Viro 	dget(pipe_dentry);
1350c5ef6035SDavid Howells 	__rpc_rmpipe(d_inode(clnt_dir), pipe_dentry);
135123e66ba9SJeff Layton 	__rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1);
135223e66ba9SJeff Layton 	__rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1);
135323e66ba9SJeff Layton 	dput(pipe_dentry);
135423e66ba9SJeff Layton }
135523e66ba9SJeff Layton 
13561da177e4SLinus Torvalds static int
1357b9662f31SDavid Howells rpc_fill_super(struct super_block *sb, struct fs_context *fc)
13581da177e4SLinus Torvalds {
13591da177e4SLinus Torvalds 	struct inode *inode;
13604b9a445eSJeff Layton 	struct dentry *root, *gssd_dentry;
1361b9662f31SDavid Howells 	struct net *net = sb->s_fs_info;
136290c4e829SStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
13632d00131aSStanislav Kinsbursky 	int err;
13641da177e4SLinus Torvalds 
136509cbfeafSKirill A. Shutemov 	sb->s_blocksize = PAGE_SIZE;
136609cbfeafSKirill A. Shutemov 	sb->s_blocksize_bits = PAGE_SHIFT;
13671da177e4SLinus Torvalds 	sb->s_magic = RPCAUTH_GSSMAGIC;
13681da177e4SLinus Torvalds 	sb->s_op = &s_ops;
1369b26d4cd3SAl Viro 	sb->s_d_op = &simple_dentry_operations;
13701da177e4SLinus Torvalds 	sb->s_time_gran = 1;
13711da177e4SLinus Torvalds 
1372d6444062SJoe Perches 	inode = rpc_get_inode(sb, S_IFDIR | 0555);
137348fde701SAl Viro 	sb->s_root = root = d_make_root(inode);
137448fde701SAl Viro 	if (!root)
13751da177e4SLinus Torvalds 		return -ENOMEM;
1376ac6feceeSTrond Myklebust 	if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
13771da177e4SLinus Torvalds 		return -ENOMEM;
13784b9a445eSJeff Layton 
13794b9a445eSJeff Layton 	gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy);
13804b9a445eSJeff Layton 	if (IS_ERR(gssd_dentry)) {
13814b9a445eSJeff Layton 		__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
13824b9a445eSJeff Layton 		return PTR_ERR(gssd_dentry);
13834b9a445eSJeff Layton 	}
13844b9a445eSJeff Layton 
13856c67a3e4SVasily Averin 	dprintk("RPC:       sending pipefs MOUNT notification for net %x%s\n",
13866c67a3e4SVasily Averin 		net->ns.inum, NET_NAME(net));
138738481605SStanislav Kinsbursky 	mutex_lock(&sn->pipefs_sb_lock);
138837629b57SStanislav Kinsbursky 	sn->pipefs_sb = sb;
13892d00131aSStanislav Kinsbursky 	err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
13902d00131aSStanislav Kinsbursky 					   RPC_PIPEFS_MOUNT,
13912d00131aSStanislav Kinsbursky 					   sb);
13922d00131aSStanislav Kinsbursky 	if (err)
13932d00131aSStanislav Kinsbursky 		goto err_depopulate;
139438481605SStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1395fc7bed8cSAl Viro 	return 0;
13962d00131aSStanislav Kinsbursky 
13972d00131aSStanislav Kinsbursky err_depopulate:
139823e66ba9SJeff Layton 	rpc_gssd_dummy_depopulate(gssd_dentry);
13992d00131aSStanislav Kinsbursky 	blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
14002d00131aSStanislav Kinsbursky 					   RPC_PIPEFS_UMOUNT,
14012d00131aSStanislav Kinsbursky 					   sb);
140237629b57SStanislav Kinsbursky 	sn->pipefs_sb = NULL;
14032d00131aSStanislav Kinsbursky 	__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
140438481605SStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
14052d00131aSStanislav Kinsbursky 	return err;
14061da177e4SLinus Torvalds }
14071da177e4SLinus Torvalds 
140889f84243SJeff Layton bool
140989f84243SJeff Layton gssd_running(struct net *net)
141089f84243SJeff Layton {
141189f84243SJeff Layton 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
141289f84243SJeff Layton 	struct rpc_pipe *pipe = sn->gssd_dummy;
141389f84243SJeff Layton 
141489f84243SJeff Layton 	return pipe->nreaders || pipe->nwriters;
141589f84243SJeff Layton }
141689f84243SJeff Layton EXPORT_SYMBOL_GPL(gssd_running);
141789f84243SJeff Layton 
1418b9662f31SDavid Howells static int rpc_fs_get_tree(struct fs_context *fc)
14191da177e4SLinus Torvalds {
1420533770ccSAl Viro 	return get_tree_keyed(fc, rpc_fill_super, get_net(fc->net_ns));
1421b9662f31SDavid Howells }
1422b9662f31SDavid Howells 
1423b9662f31SDavid Howells static void rpc_fs_free_fc(struct fs_context *fc)
1424b9662f31SDavid Howells {
1425b9662f31SDavid Howells 	if (fc->s_fs_info)
1426b9662f31SDavid Howells 		put_net(fc->s_fs_info);
1427b9662f31SDavid Howells }
1428b9662f31SDavid Howells 
1429b9662f31SDavid Howells static const struct fs_context_operations rpc_fs_context_ops = {
1430b9662f31SDavid Howells 	.free		= rpc_fs_free_fc,
1431b9662f31SDavid Howells 	.get_tree	= rpc_fs_get_tree,
1432b9662f31SDavid Howells };
1433b9662f31SDavid Howells 
1434b9662f31SDavid Howells static int rpc_init_fs_context(struct fs_context *fc)
1435b9662f31SDavid Howells {
1436b9662f31SDavid Howells 	put_user_ns(fc->user_ns);
1437b9662f31SDavid Howells 	fc->user_ns = get_user_ns(fc->net_ns->user_ns);
1438b9662f31SDavid Howells 	fc->ops = &rpc_fs_context_ops;
1439b9662f31SDavid Howells 	return 0;
14401da177e4SLinus Torvalds }
14411da177e4SLinus Torvalds 
144209acfea5STrond Myklebust static void rpc_kill_sb(struct super_block *sb)
1443021c68deSStanislav Kinsbursky {
1444021c68deSStanislav Kinsbursky 	struct net *net = sb->s_fs_info;
144590c4e829SStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1446021c68deSStanislav Kinsbursky 
1447c21a588fSStanislav Kinsbursky 	mutex_lock(&sn->pipefs_sb_lock);
1448642fe4d0STrond Myklebust 	if (sn->pipefs_sb != sb) {
1449642fe4d0STrond Myklebust 		mutex_unlock(&sn->pipefs_sb_lock);
1450642fe4d0STrond Myklebust 		goto out;
1451642fe4d0STrond Myklebust 	}
145290c4e829SStanislav Kinsbursky 	sn->pipefs_sb = NULL;
14536c67a3e4SVasily Averin 	dprintk("RPC:       sending pipefs UMOUNT notification for net %x%s\n",
14546c67a3e4SVasily Averin 		net->ns.inum, NET_NAME(net));
14552d00131aSStanislav Kinsbursky 	blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
14562d00131aSStanislav Kinsbursky 					   RPC_PIPEFS_UMOUNT,
14572d00131aSStanislav Kinsbursky 					   sb);
1458adb6fa7fSStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1459642fe4d0STrond Myklebust out:
1460021c68deSStanislav Kinsbursky 	kill_litter_super(sb);
1461d91ee87dSEric W. Biederman 	put_net(net);
14621da177e4SLinus Torvalds }
14631da177e4SLinus Torvalds 
14641da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type = {
14651da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
14661da177e4SLinus Torvalds 	.name		= "rpc_pipefs",
1467b9662f31SDavid Howells 	.init_fs_context = rpc_init_fs_context,
1468021c68deSStanislav Kinsbursky 	.kill_sb	= rpc_kill_sb,
14691da177e4SLinus Torvalds };
14707f78e035SEric W. Biederman MODULE_ALIAS_FS("rpc_pipefs");
1471fa7614ddSEric W. Biederman MODULE_ALIAS("rpc_pipefs");
14721da177e4SLinus Torvalds 
14731da177e4SLinus Torvalds static void
147451cc5068SAlexey Dobriyan init_once(void *foo)
14751da177e4SLinus Torvalds {
14761da177e4SLinus Torvalds 	struct rpc_inode *rpci = (struct rpc_inode *) foo;
14771da177e4SLinus Torvalds 
14781da177e4SLinus Torvalds 	inode_init_once(&rpci->vfs_inode);
14791da177e4SLinus Torvalds 	rpci->private = NULL;
1480ba9e0975SStanislav Kinsbursky 	rpci->pipe = NULL;
14811da177e4SLinus Torvalds 	init_waitqueue_head(&rpci->waitq);
14821da177e4SLinus Torvalds }
14831da177e4SLinus Torvalds 
14841da177e4SLinus Torvalds int register_rpc_pipefs(void)
14851da177e4SLinus Torvalds {
14865bd5f581SAkinobu Mita 	int err;
14875bd5f581SAkinobu Mita 
14881da177e4SLinus Torvalds 	rpc_inode_cachep = kmem_cache_create("rpc_inode_cache",
14891da177e4SLinus Torvalds 				sizeof(struct rpc_inode),
1490fffb60f9SPaul Jackson 				0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
14915d097056SVladimir Davydov 						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
149220c2df83SPaul Mundt 				init_once);
14931da177e4SLinus Torvalds 	if (!rpc_inode_cachep)
14941da177e4SLinus Torvalds 		return -ENOMEM;
149580df9d20SStanislav Kinsbursky 	err = rpc_clients_notifier_register();
149680df9d20SStanislav Kinsbursky 	if (err)
149780df9d20SStanislav Kinsbursky 		goto err_notifier;
14985bd5f581SAkinobu Mita 	err = register_filesystem(&rpc_pipe_fs_type);
149980df9d20SStanislav Kinsbursky 	if (err)
150080df9d20SStanislav Kinsbursky 		goto err_register;
150180df9d20SStanislav Kinsbursky 	return 0;
150280df9d20SStanislav Kinsbursky 
150380df9d20SStanislav Kinsbursky err_register:
150480df9d20SStanislav Kinsbursky 	rpc_clients_notifier_unregister();
150580df9d20SStanislav Kinsbursky err_notifier:
15065bd5f581SAkinobu Mita 	kmem_cache_destroy(rpc_inode_cachep);
15075bd5f581SAkinobu Mita 	return err;
15085bd5f581SAkinobu Mita }
15095bd5f581SAkinobu Mita 
15101da177e4SLinus Torvalds void unregister_rpc_pipefs(void)
15111da177e4SLinus Torvalds {
151280df9d20SStanislav Kinsbursky 	rpc_clients_notifier_unregister();
15131a1d92c1SAlexey Dobriyan 	kmem_cache_destroy(rpc_inode_cachep);
15141da177e4SLinus Torvalds 	unregister_filesystem(&rpc_pipe_fs_type);
15151da177e4SLinus Torvalds }
1516