xref: /openbmc/linux/net/sunrpc/rpc_pipe.c (revision bc734e8e)
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 
rpc_pipefs_notifier_register(struct notifier_block * nb)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 
rpc_pipefs_notifier_unregister(struct notifier_block * nb)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 
rpc_purge_list(wait_queue_head_t * waitq,struct list_head * head,void (* destroy_msg)(struct rpc_pipe_msg *),int err)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
rpc_timeout_upcall_queue(struct work_struct * work)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 
rpc_pipe_generic_upcall(struct file * filp,struct rpc_pipe_msg * msg,char __user * dst,size_t buflen)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
rpc_queue_upcall(struct rpc_pipe * pipe,struct rpc_pipe_msg * msg)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
rpc_inode_setowner(struct inode * inode,void * private)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
rpc_close_pipes(struct inode * inode)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 *
rpc_alloc_inode(struct super_block * sb)1971da177e4SLinus Torvalds rpc_alloc_inode(struct super_block *sb)
1981da177e4SLinus Torvalds {
1991da177e4SLinus Torvalds 	struct rpc_inode *rpci;
200fd60b288SMuchun Song 	rpci = alloc_inode_sb(sb, 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
rpc_free_inode(struct inode * inode)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
rpc_pipe_open(struct inode * inode,struct file * filp)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
rpc_pipe_release(struct inode * inode,struct file * filp)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
rpc_pipe_read(struct file * filp,char __user * buf,size_t len,loff_t * offset)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
rpc_pipe_write(struct file * filp,const char __user * buf,size_t len,loff_t * offset)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
rpc_pipe_poll(struct file * filp,struct poll_table_struct * wait)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
rpc_pipe_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)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
rpc_show_info(struct seq_file * m,void * v)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
rpc_info_open(struct inode * inode,struct file * file)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;
42671d3d0ebSTrond Myklebust 		if (clnt != NULL && refcount_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
rpc_info_release(struct inode * inode,struct file * file)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 *
rpc_get_inode(struct super_block * sb,umode_t mode)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;
475*bc734e8eSJeff Layton 	inode->i_atime = inode->i_mtime = inode_set_ctime_current(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);
48193f479d3SGustavo A. R. Silva 		break;
4821da177e4SLinus Torvalds 	default:
4831da177e4SLinus Torvalds 		break;
4841da177e4SLinus Torvalds 	}
4851da177e4SLinus Torvalds 	return inode;
4861da177e4SLinus Torvalds }
4871da177e4SLinus Torvalds 
__rpc_create_common(struct inode * dir,struct dentry * dentry,umode_t mode,const struct file_operations * i_fop,void * private)4887589806eSTrond Myklebust static int __rpc_create_common(struct inode *dir, struct dentry *dentry,
4897589806eSTrond Myklebust 			       umode_t mode,
4907589806eSTrond Myklebust 			       const struct file_operations *i_fop,
4917589806eSTrond Myklebust 			       void *private)
4927589806eSTrond Myklebust {
4937589806eSTrond Myklebust 	struct inode *inode;
4947589806eSTrond Myklebust 
495beb0f0a9STrond Myklebust 	d_drop(dentry);
4967589806eSTrond Myklebust 	inode = rpc_get_inode(dir->i_sb, mode);
4977589806eSTrond Myklebust 	if (!inode)
4987589806eSTrond Myklebust 		goto out_err;
4997589806eSTrond Myklebust 	inode->i_ino = iunique(dir->i_sb, 100);
5007589806eSTrond Myklebust 	if (i_fop)
5017589806eSTrond Myklebust 		inode->i_fop = i_fop;
5027589806eSTrond Myklebust 	if (private)
5037589806eSTrond Myklebust 		rpc_inode_setowner(inode, private);
5047589806eSTrond Myklebust 	d_add(dentry, inode);
5057589806eSTrond Myklebust 	return 0;
5067589806eSTrond Myklebust out_err:
5071e903edaSAl Viro 	printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %pd\n",
5081e903edaSAl Viro 			__FILE__, __func__, dentry);
5097589806eSTrond Myklebust 	dput(dentry);
5107589806eSTrond Myklebust 	return -ENOMEM;
5117589806eSTrond Myklebust }
5127589806eSTrond Myklebust 
__rpc_create(struct inode * dir,struct dentry * dentry,umode_t mode,const struct file_operations * i_fop,void * private)513ac6feceeSTrond Myklebust static int __rpc_create(struct inode *dir, struct dentry *dentry,
514ac6feceeSTrond Myklebust 			umode_t mode,
515ac6feceeSTrond Myklebust 			const struct file_operations *i_fop,
516ac6feceeSTrond Myklebust 			void *private)
517ac6feceeSTrond Myklebust {
518ac6feceeSTrond Myklebust 	int err;
519ac6feceeSTrond Myklebust 
520ac6feceeSTrond Myklebust 	err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private);
521ac6feceeSTrond Myklebust 	if (err)
522ac6feceeSTrond Myklebust 		return err;
523ac6feceeSTrond Myklebust 	fsnotify_create(dir, dentry);
524ac6feceeSTrond Myklebust 	return 0;
525ac6feceeSTrond Myklebust }
526ac6feceeSTrond Myklebust 
__rpc_mkdir(struct inode * dir,struct dentry * dentry,umode_t mode,const struct file_operations * i_fop,void * private)5277589806eSTrond Myklebust static int __rpc_mkdir(struct inode *dir, struct dentry *dentry,
5287589806eSTrond Myklebust 		       umode_t mode,
5297589806eSTrond Myklebust 		       const struct file_operations *i_fop,
5307589806eSTrond Myklebust 		       void *private)
5317589806eSTrond Myklebust {
5327589806eSTrond Myklebust 	int err;
5337589806eSTrond Myklebust 
5347589806eSTrond Myklebust 	err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private);
5357589806eSTrond Myklebust 	if (err)
5367589806eSTrond Myklebust 		return err;
5377589806eSTrond Myklebust 	inc_nlink(dir);
5387589806eSTrond Myklebust 	fsnotify_mkdir(dir, dentry);
5397589806eSTrond Myklebust 	return 0;
5407589806eSTrond Myklebust }
5417589806eSTrond Myklebust 
542ba9e0975SStanislav Kinsbursky static void
init_pipe(struct rpc_pipe * pipe)543ba9e0975SStanislav Kinsbursky init_pipe(struct rpc_pipe *pipe)
544ba9e0975SStanislav Kinsbursky {
545ba9e0975SStanislav Kinsbursky 	pipe->nreaders = 0;
546ba9e0975SStanislav Kinsbursky 	pipe->nwriters = 0;
547ba9e0975SStanislav Kinsbursky 	INIT_LIST_HEAD(&pipe->in_upcall);
548ba9e0975SStanislav Kinsbursky 	INIT_LIST_HEAD(&pipe->in_downcall);
549ba9e0975SStanislav Kinsbursky 	INIT_LIST_HEAD(&pipe->pipe);
550ba9e0975SStanislav Kinsbursky 	pipe->pipelen = 0;
551ba9e0975SStanislav Kinsbursky 	INIT_DELAYED_WORK(&pipe->queue_timeout,
552ba9e0975SStanislav Kinsbursky 			    rpc_timeout_upcall_queue);
553ba9e0975SStanislav Kinsbursky 	pipe->ops = NULL;
554ba9e0975SStanislav Kinsbursky 	spin_lock_init(&pipe->lock);
555c239d83bSStanislav Kinsbursky 	pipe->dentry = NULL;
556ba9e0975SStanislav Kinsbursky }
557ba9e0975SStanislav Kinsbursky 
rpc_destroy_pipe_data(struct rpc_pipe * pipe)558c239d83bSStanislav Kinsbursky void rpc_destroy_pipe_data(struct rpc_pipe *pipe)
559c239d83bSStanislav Kinsbursky {
560c239d83bSStanislav Kinsbursky 	kfree(pipe);
561c239d83bSStanislav Kinsbursky }
562c239d83bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_destroy_pipe_data);
563c239d83bSStanislav Kinsbursky 
rpc_mkpipe_data(const struct rpc_pipe_ops * ops,int flags)564c239d83bSStanislav Kinsbursky struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags)
5657589806eSTrond Myklebust {
566ba9e0975SStanislav Kinsbursky 	struct rpc_pipe *pipe;
5677589806eSTrond Myklebust 
568ba9e0975SStanislav Kinsbursky 	pipe = kzalloc(sizeof(struct rpc_pipe), GFP_KERNEL);
569ba9e0975SStanislav Kinsbursky 	if (!pipe)
570c239d83bSStanislav Kinsbursky 		return ERR_PTR(-ENOMEM);
571ba9e0975SStanislav Kinsbursky 	init_pipe(pipe);
572c239d83bSStanislav Kinsbursky 	pipe->ops = ops;
573c239d83bSStanislav Kinsbursky 	pipe->flags = flags;
574c239d83bSStanislav Kinsbursky 	return pipe;
575ba9e0975SStanislav Kinsbursky }
576c239d83bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_mkpipe_data);
577c239d83bSStanislav Kinsbursky 
__rpc_mkpipe_dentry(struct inode * dir,struct dentry * dentry,umode_t mode,const struct file_operations * i_fop,void * private,struct rpc_pipe * pipe)578c239d83bSStanislav Kinsbursky static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
5797589806eSTrond Myklebust 			       umode_t mode,
5807589806eSTrond Myklebust 			       const struct file_operations *i_fop,
5817589806eSTrond Myklebust 			       void *private,
582c239d83bSStanislav Kinsbursky 			       struct rpc_pipe *pipe)
5837589806eSTrond Myklebust {
5847589806eSTrond Myklebust 	struct rpc_inode *rpci;
5857589806eSTrond Myklebust 	int err;
5867589806eSTrond Myklebust 
5877589806eSTrond Myklebust 	err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private);
5887589806eSTrond Myklebust 	if (err)
5897589806eSTrond Myklebust 		return err;
590c5ef6035SDavid Howells 	rpci = RPC_I(d_inode(dentry));
5917589806eSTrond Myklebust 	rpci->private = private;
592ba9e0975SStanislav Kinsbursky 	rpci->pipe = pipe;
5937589806eSTrond Myklebust 	fsnotify_create(dir, dentry);
5947589806eSTrond Myklebust 	return 0;
5957589806eSTrond Myklebust }
5967589806eSTrond Myklebust 
__rpc_rmdir(struct inode * dir,struct dentry * dentry)597ac6feceeSTrond Myklebust static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
598ac6feceeSTrond Myklebust {
599ac6feceeSTrond Myklebust 	int ret;
600ac6feceeSTrond Myklebust 
601ac6feceeSTrond Myklebust 	dget(dentry);
602ac6feceeSTrond Myklebust 	ret = simple_rmdir(dir, dentry);
60329044daeSAmir Goldstein 	d_drop(dentry);
604a35d632cSAmir Goldstein 	if (!ret)
605a35d632cSAmir Goldstein 		fsnotify_rmdir(dir, dentry);
606ac6feceeSTrond Myklebust 	dput(dentry);
607ac6feceeSTrond Myklebust 	return ret;
608ac6feceeSTrond Myklebust }
609ac6feceeSTrond Myklebust 
__rpc_unlink(struct inode * dir,struct dentry * dentry)610810d90bcSTrond Myklebust static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
611810d90bcSTrond Myklebust {
612810d90bcSTrond Myklebust 	int ret;
613810d90bcSTrond Myklebust 
614810d90bcSTrond Myklebust 	dget(dentry);
615810d90bcSTrond Myklebust 	ret = simple_unlink(dir, dentry);
61629044daeSAmir Goldstein 	d_drop(dentry);
617a35d632cSAmir Goldstein 	if (!ret)
618a35d632cSAmir Goldstein 		fsnotify_unlink(dir, dentry);
619810d90bcSTrond Myklebust 	dput(dentry);
620810d90bcSTrond Myklebust 	return ret;
621810d90bcSTrond Myklebust }
622810d90bcSTrond Myklebust 
__rpc_rmpipe(struct inode * dir,struct dentry * dentry)623810d90bcSTrond Myklebust static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry)
624810d90bcSTrond Myklebust {
625c5ef6035SDavid Howells 	struct inode *inode = d_inode(dentry);
626810d90bcSTrond Myklebust 
627810d90bcSTrond Myklebust 	rpc_close_pipes(inode);
628810d90bcSTrond Myklebust 	return __rpc_unlink(dir, dentry);
629810d90bcSTrond Myklebust }
630810d90bcSTrond Myklebust 
__rpc_lookup_create_exclusive(struct dentry * parent,const char * name)631cfeaa4a3STrond Myklebust static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
632d3db90b0SAl Viro 					  const char *name)
633cfeaa4a3STrond Myklebust {
634d3db90b0SAl Viro 	struct qstr q = QSTR_INIT(name, strlen(name));
635d3db90b0SAl Viro 	struct dentry *dentry = d_hash_and_lookup(parent, &q);
6365bff0386SStanislav Kinsbursky 	if (!dentry) {
637d3db90b0SAl Viro 		dentry = d_alloc(parent, &q);
6385bff0386SStanislav Kinsbursky 		if (!dentry)
6395bff0386SStanislav Kinsbursky 			return ERR_PTR(-ENOMEM);
6405bff0386SStanislav Kinsbursky 	}
641c5ef6035SDavid Howells 	if (d_really_is_negative(dentry))
642f1f0abe1SDan Carpenter 		return dentry;
643cfeaa4a3STrond Myklebust 	dput(dentry);
644cfeaa4a3STrond Myklebust 	return ERR_PTR(-EEXIST);
645cfeaa4a3STrond Myklebust }
646cfeaa4a3STrond Myklebust 
6471da177e4SLinus Torvalds /*
6481da177e4SLinus Torvalds  * FIXME: This probably has races.
6491da177e4SLinus Torvalds  */
__rpc_depopulate(struct dentry * parent,const struct rpc_filelist * files,int start,int eof)650ac6feceeSTrond Myklebust static void __rpc_depopulate(struct dentry *parent,
651ac6feceeSTrond Myklebust 			     const struct rpc_filelist *files,
652ac6feceeSTrond Myklebust 			     int start, int eof)
6531da177e4SLinus Torvalds {
654c5ef6035SDavid Howells 	struct inode *dir = d_inode(parent);
655ac6feceeSTrond Myklebust 	struct dentry *dentry;
656ac6feceeSTrond Myklebust 	struct qstr name;
657ac6feceeSTrond Myklebust 	int i;
658ac6feceeSTrond Myklebust 
659ac6feceeSTrond Myklebust 	for (i = start; i < eof; i++) {
660ac6feceeSTrond Myklebust 		name.name = files[i].name;
661ac6feceeSTrond Myklebust 		name.len = strlen(files[i].name);
662d3db90b0SAl Viro 		dentry = d_hash_and_lookup(parent, &name);
663ac6feceeSTrond Myklebust 
664ac6feceeSTrond Myklebust 		if (dentry == NULL)
665ac6feceeSTrond Myklebust 			continue;
666c5ef6035SDavid Howells 		if (d_really_is_negative(dentry))
667ac6feceeSTrond Myklebust 			goto next;
668c5ef6035SDavid Howells 		switch (d_inode(dentry)->i_mode & S_IFMT) {
669ac6feceeSTrond Myklebust 			default:
670ac6feceeSTrond Myklebust 				BUG();
671ac6feceeSTrond Myklebust 			case S_IFREG:
672ac6feceeSTrond Myklebust 				__rpc_unlink(dir, dentry);
673ac6feceeSTrond Myklebust 				break;
674ac6feceeSTrond Myklebust 			case S_IFDIR:
675ac6feceeSTrond Myklebust 				__rpc_rmdir(dir, dentry);
676ac6feceeSTrond Myklebust 		}
677ac6feceeSTrond Myklebust next:
678ac6feceeSTrond Myklebust 		dput(dentry);
679ac6feceeSTrond Myklebust 	}
680ac6feceeSTrond Myklebust }
681ac6feceeSTrond Myklebust 
rpc_depopulate(struct dentry * parent,const struct rpc_filelist * files,int start,int eof)682ac6feceeSTrond Myklebust static void rpc_depopulate(struct dentry *parent,
683ac6feceeSTrond Myklebust 			   const struct rpc_filelist *files,
684ac6feceeSTrond Myklebust 			   int start, int eof)
685ac6feceeSTrond Myklebust {
686c5ef6035SDavid Howells 	struct inode *dir = d_inode(parent);
6871da177e4SLinus Torvalds 
6885955102cSAl Viro 	inode_lock_nested(dir, I_MUTEX_CHILD);
689ac6feceeSTrond Myklebust 	__rpc_depopulate(parent, files, start, eof);
6905955102cSAl Viro 	inode_unlock(dir);
6911da177e4SLinus Torvalds }
6921da177e4SLinus Torvalds 
rpc_populate(struct dentry * parent,const struct rpc_filelist * files,int start,int eof,void * private)693ac6feceeSTrond Myklebust static int rpc_populate(struct dentry *parent,
694ac6feceeSTrond Myklebust 			const struct rpc_filelist *files,
695ac6feceeSTrond Myklebust 			int start, int eof,
696ac6feceeSTrond Myklebust 			void *private)
6971da177e4SLinus Torvalds {
698c5ef6035SDavid Howells 	struct inode *dir = d_inode(parent);
6991da177e4SLinus Torvalds 	struct dentry *dentry;
700ac6feceeSTrond Myklebust 	int i, err;
7011da177e4SLinus Torvalds 
7025955102cSAl Viro 	inode_lock(dir);
7031da177e4SLinus Torvalds 	for (i = start; i < eof; i++) {
704d3db90b0SAl Viro 		dentry = __rpc_lookup_create_exclusive(parent, files[i].name);
705ac6feceeSTrond Myklebust 		err = PTR_ERR(dentry);
706ac6feceeSTrond Myklebust 		if (IS_ERR(dentry))
7071da177e4SLinus Torvalds 			goto out_bad;
708ac6feceeSTrond Myklebust 		switch (files[i].mode & S_IFMT) {
709ac6feceeSTrond Myklebust 			default:
710ac6feceeSTrond Myklebust 				BUG();
711ac6feceeSTrond Myklebust 			case S_IFREG:
712ac6feceeSTrond Myklebust 				err = __rpc_create(dir, dentry,
713ac6feceeSTrond Myklebust 						files[i].mode,
714ac6feceeSTrond Myklebust 						files[i].i_fop,
715ac6feceeSTrond Myklebust 						private);
716ac6feceeSTrond Myklebust 				break;
717ac6feceeSTrond Myklebust 			case S_IFDIR:
718ac6feceeSTrond Myklebust 				err = __rpc_mkdir(dir, dentry,
719ac6feceeSTrond Myklebust 						files[i].mode,
720ac6feceeSTrond Myklebust 						NULL,
721ac6feceeSTrond Myklebust 						private);
7221da177e4SLinus Torvalds 		}
723ac6feceeSTrond Myklebust 		if (err != 0)
724ac6feceeSTrond Myklebust 			goto out_bad;
7251da177e4SLinus Torvalds 	}
7265955102cSAl Viro 	inode_unlock(dir);
7271da177e4SLinus Torvalds 	return 0;
7281da177e4SLinus Torvalds out_bad:
729ac6feceeSTrond Myklebust 	__rpc_depopulate(parent, files, start, eof);
7305955102cSAl Viro 	inode_unlock(dir);
7311e903edaSAl Viro 	printk(KERN_WARNING "%s: %s failed to populate directory %pd\n",
7321e903edaSAl Viro 			__FILE__, __func__, parent);
733ac6feceeSTrond Myklebust 	return err;
734f134585aSTrond Myklebust }
735f134585aSTrond Myklebust 
rpc_mkdir_populate(struct dentry * parent,const char * name,umode_t mode,void * private,int (* populate)(struct dentry *,void *),void * args_populate)736e57aed77STrond Myklebust static struct dentry *rpc_mkdir_populate(struct dentry *parent,
737a95e691fSAl Viro 		const char *name, umode_t mode, void *private,
738e57aed77STrond Myklebust 		int (*populate)(struct dentry *, void *), void *args_populate)
739f134585aSTrond Myklebust {
740f134585aSTrond Myklebust 	struct dentry *dentry;
741c5ef6035SDavid Howells 	struct inode *dir = d_inode(parent);
742f134585aSTrond Myklebust 	int error;
743f134585aSTrond Myklebust 
7445955102cSAl Viro 	inode_lock_nested(dir, I_MUTEX_PARENT);
7457d59d1e8STrond Myklebust 	dentry = __rpc_lookup_create_exclusive(parent, name);
746f134585aSTrond Myklebust 	if (IS_ERR(dentry))
7477d59d1e8STrond Myklebust 		goto out;
7487d59d1e8STrond Myklebust 	error = __rpc_mkdir(dir, dentry, mode, NULL, private);
7497589806eSTrond Myklebust 	if (error != 0)
7507589806eSTrond Myklebust 		goto out_err;
751e57aed77STrond Myklebust 	if (populate != NULL) {
752e57aed77STrond Myklebust 		error = populate(dentry, args_populate);
753f134585aSTrond Myklebust 		if (error)
754ac6feceeSTrond Myklebust 			goto err_rmdir;
755e57aed77STrond Myklebust 	}
756f134585aSTrond Myklebust out:
7575955102cSAl Viro 	inode_unlock(dir);
7585c3e985aSTrond Myklebust 	return dentry;
759ac6feceeSTrond Myklebust err_rmdir:
760f134585aSTrond Myklebust 	__rpc_rmdir(dir, dentry);
7617589806eSTrond Myklebust out_err:
762f134585aSTrond Myklebust 	dentry = ERR_PTR(error);
763f134585aSTrond Myklebust 	goto out;
764f134585aSTrond Myklebust }
765f134585aSTrond Myklebust 
rpc_rmdir_depopulate(struct dentry * dentry,void (* depopulate)(struct dentry *))766e57aed77STrond Myklebust static int rpc_rmdir_depopulate(struct dentry *dentry,
767e57aed77STrond Myklebust 		void (*depopulate)(struct dentry *))
768f134585aSTrond Myklebust {
769dff02cc1STrond Myklebust 	struct dentry *parent;
770f134585aSTrond Myklebust 	struct inode *dir;
771f134585aSTrond Myklebust 	int error;
772f134585aSTrond Myklebust 
773dff02cc1STrond Myklebust 	parent = dget_parent(dentry);
774c5ef6035SDavid Howells 	dir = d_inode(parent);
7755955102cSAl Viro 	inode_lock_nested(dir, I_MUTEX_PARENT);
776e57aed77STrond Myklebust 	if (depopulate != NULL)
777e57aed77STrond Myklebust 		depopulate(dentry);
778f134585aSTrond Myklebust 	error = __rpc_rmdir(dir, dentry);
7795955102cSAl Viro 	inode_unlock(dir);
780dff02cc1STrond Myklebust 	dput(parent);
781f134585aSTrond Myklebust 	return error;
782f134585aSTrond Myklebust }
7831da177e4SLinus Torvalds 
78493a44a75SJ. Bruce Fields /**
785c1639be9SMauro Carvalho Chehab  * rpc_mkpipe_dentry - make an rpc_pipefs file for kernel<->userspace
786c1639be9SMauro Carvalho Chehab  *		       communication
78793a44a75SJ. Bruce Fields  * @parent: dentry of directory to create new "pipe" in
78893a44a75SJ. Bruce Fields  * @name: name of pipe
78993a44a75SJ. Bruce Fields  * @private: private data to associate with the pipe, for the caller's use
790bda14606SRandy Dunlap  * @pipe: &rpc_pipe containing input parameters
79193a44a75SJ. Bruce Fields  *
79293a44a75SJ. Bruce Fields  * Data is made available for userspace to read by calls to
79393a44a75SJ. Bruce Fields  * rpc_queue_upcall().  The actual reads will result in calls to
79493a44a75SJ. Bruce Fields  * @ops->upcall, which will be called with the file pointer,
79593a44a75SJ. Bruce Fields  * message, and userspace buffer to copy to.
79693a44a75SJ. Bruce Fields  *
79793a44a75SJ. Bruce Fields  * Writes can come at any time, and do not necessarily have to be
79893a44a75SJ. Bruce Fields  * responses to upcalls.  They will result in calls to @msg->downcall.
79993a44a75SJ. Bruce Fields  *
80093a44a75SJ. Bruce Fields  * The @private argument passed here will be available to all these methods
801496ad9aaSAl Viro  * from the file pointer, via RPC_I(file_inode(file))->private.
80293a44a75SJ. Bruce Fields  */
rpc_mkpipe_dentry(struct dentry * parent,const char * name,void * private,struct rpc_pipe * pipe)803c239d83bSStanislav Kinsbursky struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name,
804c239d83bSStanislav Kinsbursky 				 void *private, struct rpc_pipe *pipe)
8051da177e4SLinus Torvalds {
8061da177e4SLinus Torvalds 	struct dentry *dentry;
807c5ef6035SDavid Howells 	struct inode *dir = d_inode(parent);
808d6444062SJoe Perches 	umode_t umode = S_IFIFO | 0600;
8097589806eSTrond Myklebust 	int err;
8107364af6aSTrond Myklebust 
811c239d83bSStanislav Kinsbursky 	if (pipe->ops->upcall == NULL)
812d6444062SJoe Perches 		umode &= ~0444;
813c239d83bSStanislav Kinsbursky 	if (pipe->ops->downcall == NULL)
814d6444062SJoe Perches 		umode &= ~0222;
8151da177e4SLinus Torvalds 
8165955102cSAl Viro 	inode_lock_nested(dir, I_MUTEX_PARENT);
817d3db90b0SAl Viro 	dentry = __rpc_lookup_create_exclusive(parent, name);
8181da177e4SLinus Torvalds 	if (IS_ERR(dentry))
819cfeaa4a3STrond Myklebust 		goto out;
820c239d83bSStanislav Kinsbursky 	err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops,
821c239d83bSStanislav Kinsbursky 				  private, pipe);
8227589806eSTrond Myklebust 	if (err)
8237589806eSTrond Myklebust 		goto out_err;
824f134585aSTrond Myklebust out:
8255955102cSAl Viro 	inode_unlock(dir);
8265c3e985aSTrond Myklebust 	return dentry;
8277589806eSTrond Myklebust out_err:
8287589806eSTrond Myklebust 	dentry = ERR_PTR(err);
8291e903edaSAl Viro 	printk(KERN_WARNING "%s: %s() failed to create pipe %pd/%s (errno = %d)\n",
8301e903edaSAl Viro 			__FILE__, __func__, parent, name,
8317589806eSTrond Myklebust 			err);
832f134585aSTrond Myklebust 	goto out;
8331da177e4SLinus Torvalds }
834c239d83bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry);
8351da177e4SLinus Torvalds 
83693a44a75SJ. Bruce Fields /**
83793a44a75SJ. Bruce Fields  * rpc_unlink - remove a pipe
83893a44a75SJ. Bruce Fields  * @dentry: dentry for the pipe, as returned from rpc_mkpipe
83993a44a75SJ. Bruce Fields  *
84093a44a75SJ. Bruce Fields  * After this call, lookups will no longer find the pipe, and any
84193a44a75SJ. Bruce Fields  * attempts to read or write using preexisting opens of the pipe will
84293a44a75SJ. Bruce Fields  * return -EPIPE.
84393a44a75SJ. Bruce Fields  */
844f134585aSTrond Myklebust int
rpc_unlink(struct dentry * dentry)8455d67476fSTrond Myklebust rpc_unlink(struct dentry *dentry)
8461da177e4SLinus Torvalds {
8475d67476fSTrond Myklebust 	struct dentry *parent;
848f134585aSTrond Myklebust 	struct inode *dir;
8495d67476fSTrond Myklebust 	int error = 0;
8501da177e4SLinus Torvalds 
8515d67476fSTrond Myklebust 	parent = dget_parent(dentry);
852c5ef6035SDavid Howells 	dir = d_inode(parent);
8535955102cSAl Viro 	inode_lock_nested(dir, I_MUTEX_PARENT);
854810d90bcSTrond Myklebust 	error = __rpc_rmpipe(dir, dentry);
8555955102cSAl Viro 	inode_unlock(dir);
8565d67476fSTrond Myklebust 	dput(parent);
857f134585aSTrond Myklebust 	return error;
8581da177e4SLinus Torvalds }
859468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_unlink);
8601da177e4SLinus Torvalds 
8616739ffb7STrond Myklebust /**
8626739ffb7STrond Myklebust  * rpc_init_pipe_dir_head - initialise a struct rpc_pipe_dir_head
8636739ffb7STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
8646739ffb7STrond Myklebust  */
rpc_init_pipe_dir_head(struct rpc_pipe_dir_head * pdh)8656739ffb7STrond Myklebust void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh)
8666739ffb7STrond Myklebust {
8676739ffb7STrond Myklebust 	INIT_LIST_HEAD(&pdh->pdh_entries);
8686739ffb7STrond Myklebust 	pdh->pdh_dentry = NULL;
8696739ffb7STrond Myklebust }
8706739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_head);
8716739ffb7STrond Myklebust 
8726739ffb7STrond Myklebust /**
8736739ffb7STrond Myklebust  * rpc_init_pipe_dir_object - initialise a struct rpc_pipe_dir_object
8746739ffb7STrond Myklebust  * @pdo: pointer to struct rpc_pipe_dir_object
8756739ffb7STrond Myklebust  * @pdo_ops: pointer to const struct rpc_pipe_dir_object_ops
8766739ffb7STrond Myklebust  * @pdo_data: pointer to caller-defined data
8776739ffb7STrond Myklebust  */
rpc_init_pipe_dir_object(struct rpc_pipe_dir_object * pdo,const struct rpc_pipe_dir_object_ops * pdo_ops,void * pdo_data)8786739ffb7STrond Myklebust void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo,
8796739ffb7STrond Myklebust 		const struct rpc_pipe_dir_object_ops *pdo_ops,
8806739ffb7STrond Myklebust 		void *pdo_data)
8816739ffb7STrond Myklebust {
8826739ffb7STrond Myklebust 	INIT_LIST_HEAD(&pdo->pdo_head);
8836739ffb7STrond Myklebust 	pdo->pdo_ops = pdo_ops;
8846739ffb7STrond Myklebust 	pdo->pdo_data = pdo_data;
8856739ffb7STrond Myklebust }
8866739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_object);
8876739ffb7STrond Myklebust 
8886739ffb7STrond Myklebust static int
rpc_add_pipe_dir_object_locked(struct net * net,struct rpc_pipe_dir_head * pdh,struct rpc_pipe_dir_object * pdo)8896739ffb7STrond Myklebust rpc_add_pipe_dir_object_locked(struct net *net,
8906739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
8916739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
8926739ffb7STrond Myklebust {
8936739ffb7STrond Myklebust 	int ret = 0;
8946739ffb7STrond Myklebust 
8956739ffb7STrond Myklebust 	if (pdh->pdh_dentry)
8966739ffb7STrond Myklebust 		ret = pdo->pdo_ops->create(pdh->pdh_dentry, pdo);
8976739ffb7STrond Myklebust 	if (ret == 0)
8986739ffb7STrond Myklebust 		list_add_tail(&pdo->pdo_head, &pdh->pdh_entries);
8996739ffb7STrond Myklebust 	return ret;
9006739ffb7STrond Myklebust }
9016739ffb7STrond Myklebust 
9026739ffb7STrond Myklebust static void
rpc_remove_pipe_dir_object_locked(struct net * net,struct rpc_pipe_dir_head * pdh,struct rpc_pipe_dir_object * pdo)9036739ffb7STrond Myklebust rpc_remove_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 	if (pdh->pdh_dentry)
9086739ffb7STrond Myklebust 		pdo->pdo_ops->destroy(pdh->pdh_dentry, pdo);
9096739ffb7STrond Myklebust 	list_del_init(&pdo->pdo_head);
9106739ffb7STrond Myklebust }
9116739ffb7STrond Myklebust 
9126739ffb7STrond Myklebust /**
9136739ffb7STrond Myklebust  * rpc_add_pipe_dir_object - associate a rpc_pipe_dir_object to a directory
9146739ffb7STrond Myklebust  * @net: pointer to struct net
9156739ffb7STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
9166739ffb7STrond Myklebust  * @pdo: pointer to struct rpc_pipe_dir_object
9176739ffb7STrond Myklebust  *
9186739ffb7STrond Myklebust  */
9196739ffb7STrond Myklebust int
rpc_add_pipe_dir_object(struct net * net,struct rpc_pipe_dir_head * pdh,struct rpc_pipe_dir_object * pdo)9206739ffb7STrond Myklebust rpc_add_pipe_dir_object(struct net *net,
9216739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
9226739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
9236739ffb7STrond Myklebust {
9246739ffb7STrond Myklebust 	int ret = 0;
9256739ffb7STrond Myklebust 
9266739ffb7STrond Myklebust 	if (list_empty(&pdo->pdo_head)) {
9276739ffb7STrond Myklebust 		struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
9286739ffb7STrond Myklebust 
9296739ffb7STrond Myklebust 		mutex_lock(&sn->pipefs_sb_lock);
9306739ffb7STrond Myklebust 		ret = rpc_add_pipe_dir_object_locked(net, pdh, pdo);
9316739ffb7STrond Myklebust 		mutex_unlock(&sn->pipefs_sb_lock);
9326739ffb7STrond Myklebust 	}
9336739ffb7STrond Myklebust 	return ret;
9346739ffb7STrond Myklebust }
9356739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_add_pipe_dir_object);
9366739ffb7STrond Myklebust 
9376739ffb7STrond Myklebust /**
9386739ffb7STrond Myklebust  * rpc_remove_pipe_dir_object - remove a rpc_pipe_dir_object from a directory
9396739ffb7STrond Myklebust  * @net: pointer to struct net
9406739ffb7STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
9416739ffb7STrond Myklebust  * @pdo: pointer to struct rpc_pipe_dir_object
9426739ffb7STrond Myklebust  *
9436739ffb7STrond Myklebust  */
9446739ffb7STrond Myklebust void
rpc_remove_pipe_dir_object(struct net * net,struct rpc_pipe_dir_head * pdh,struct rpc_pipe_dir_object * pdo)9456739ffb7STrond Myklebust rpc_remove_pipe_dir_object(struct net *net,
9466739ffb7STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
9476739ffb7STrond Myklebust 		struct rpc_pipe_dir_object *pdo)
9486739ffb7STrond Myklebust {
9496739ffb7STrond Myklebust 	if (!list_empty(&pdo->pdo_head)) {
9506739ffb7STrond Myklebust 		struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
9516739ffb7STrond Myklebust 
9526739ffb7STrond Myklebust 		mutex_lock(&sn->pipefs_sb_lock);
9536739ffb7STrond Myklebust 		rpc_remove_pipe_dir_object_locked(net, pdh, pdo);
9546739ffb7STrond Myklebust 		mutex_unlock(&sn->pipefs_sb_lock);
9556739ffb7STrond Myklebust 	}
9566739ffb7STrond Myklebust }
9576739ffb7STrond Myklebust EXPORT_SYMBOL_GPL(rpc_remove_pipe_dir_object);
9586739ffb7STrond Myklebust 
959298fc355STrond Myklebust /**
960298fc355STrond Myklebust  * rpc_find_or_alloc_pipe_dir_object
961298fc355STrond Myklebust  * @net: pointer to struct net
962298fc355STrond Myklebust  * @pdh: pointer to struct rpc_pipe_dir_head
963298fc355STrond Myklebust  * @match: match struct rpc_pipe_dir_object to data
964298fc355STrond Myklebust  * @alloc: allocate a new struct rpc_pipe_dir_object
965298fc355STrond Myklebust  * @data: user defined data for match() and alloc()
966298fc355STrond Myklebust  *
967298fc355STrond Myklebust  */
968298fc355STrond Myklebust struct rpc_pipe_dir_object *
rpc_find_or_alloc_pipe_dir_object(struct net * net,struct rpc_pipe_dir_head * pdh,int (* match)(struct rpc_pipe_dir_object *,void *),struct rpc_pipe_dir_object * (* alloc)(void *),void * data)969298fc355STrond Myklebust rpc_find_or_alloc_pipe_dir_object(struct net *net,
970298fc355STrond Myklebust 		struct rpc_pipe_dir_head *pdh,
971298fc355STrond Myklebust 		int (*match)(struct rpc_pipe_dir_object *, void *),
972298fc355STrond Myklebust 		struct rpc_pipe_dir_object *(*alloc)(void *),
973298fc355STrond Myklebust 		void *data)
974298fc355STrond Myklebust {
975298fc355STrond Myklebust 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
976298fc355STrond Myklebust 	struct rpc_pipe_dir_object *pdo;
977298fc355STrond Myklebust 
978298fc355STrond Myklebust 	mutex_lock(&sn->pipefs_sb_lock);
979298fc355STrond Myklebust 	list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) {
980298fc355STrond Myklebust 		if (!match(pdo, data))
981298fc355STrond Myklebust 			continue;
982298fc355STrond Myklebust 		goto out;
983298fc355STrond Myklebust 	}
984298fc355STrond Myklebust 	pdo = alloc(data);
985298fc355STrond Myklebust 	if (!pdo)
986298fc355STrond Myklebust 		goto out;
987298fc355STrond Myklebust 	rpc_add_pipe_dir_object_locked(net, pdh, pdo);
988298fc355STrond Myklebust out:
989298fc355STrond Myklebust 	mutex_unlock(&sn->pipefs_sb_lock);
990298fc355STrond Myklebust 	return pdo;
991298fc355STrond Myklebust }
992298fc355STrond Myklebust EXPORT_SYMBOL_GPL(rpc_find_or_alloc_pipe_dir_object);
993298fc355STrond Myklebust 
9946739ffb7STrond Myklebust static void
rpc_create_pipe_dir_objects(struct rpc_pipe_dir_head * pdh)9956739ffb7STrond Myklebust rpc_create_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
9966739ffb7STrond Myklebust {
9976739ffb7STrond Myklebust 	struct rpc_pipe_dir_object *pdo;
9986739ffb7STrond Myklebust 	struct dentry *dir = pdh->pdh_dentry;
9996739ffb7STrond Myklebust 
10006739ffb7STrond Myklebust 	list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head)
10016739ffb7STrond Myklebust 		pdo->pdo_ops->create(dir, pdo);
10026739ffb7STrond Myklebust }
10036739ffb7STrond Myklebust 
10046739ffb7STrond Myklebust static void
rpc_destroy_pipe_dir_objects(struct rpc_pipe_dir_head * pdh)10056739ffb7STrond Myklebust rpc_destroy_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
10066739ffb7STrond Myklebust {
10076739ffb7STrond Myklebust 	struct rpc_pipe_dir_object *pdo;
10086739ffb7STrond Myklebust 	struct dentry *dir = pdh->pdh_dentry;
10096739ffb7STrond Myklebust 
10106739ffb7STrond Myklebust 	list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head)
10116739ffb7STrond Myklebust 		pdo->pdo_ops->destroy(dir, pdo);
10126739ffb7STrond Myklebust }
10136739ffb7STrond Myklebust 
1014e57aed77STrond Myklebust enum {
1015e57aed77STrond Myklebust 	RPCAUTH_info,
1016e57aed77STrond Myklebust 	RPCAUTH_EOF
1017e57aed77STrond Myklebust };
1018e57aed77STrond Myklebust 
1019e57aed77STrond Myklebust static const struct rpc_filelist authfiles[] = {
1020e57aed77STrond Myklebust 	[RPCAUTH_info] = {
1021e57aed77STrond Myklebust 		.name = "info",
1022e57aed77STrond Myklebust 		.i_fop = &rpc_info_operations,
1023d6444062SJoe Perches 		.mode = S_IFREG | 0400,
1024e57aed77STrond Myklebust 	},
1025e57aed77STrond Myklebust };
1026e57aed77STrond Myklebust 
rpc_clntdir_populate(struct dentry * dentry,void * private)1027e57aed77STrond Myklebust static int rpc_clntdir_populate(struct dentry *dentry, void *private)
1028e57aed77STrond Myklebust {
1029e57aed77STrond Myklebust 	return rpc_populate(dentry,
1030e57aed77STrond Myklebust 			    authfiles, RPCAUTH_info, RPCAUTH_EOF,
1031e57aed77STrond Myklebust 			    private);
1032e57aed77STrond Myklebust }
1033e57aed77STrond Myklebust 
rpc_clntdir_depopulate(struct dentry * dentry)1034e57aed77STrond Myklebust static void rpc_clntdir_depopulate(struct dentry *dentry)
1035e57aed77STrond Myklebust {
1036e57aed77STrond Myklebust 	rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF);
1037e57aed77STrond Myklebust }
1038e57aed77STrond Myklebust 
10397d59d1e8STrond Myklebust /**
10407d59d1e8STrond Myklebust  * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs
1041a95e691fSAl Viro  * @dentry: the parent of new directory
1042a95e691fSAl Viro  * @name: the name of new directory
10437d59d1e8STrond Myklebust  * @rpc_client: rpc client to associate with this directory
10447d59d1e8STrond Myklebust  *
10457d59d1e8STrond Myklebust  * This creates a directory at the given @path associated with
10467d59d1e8STrond Myklebust  * @rpc_clnt, which will contain a file named "info" with some basic
10477d59d1e8STrond Myklebust  * information about the client, together with any "pipes" that may
10487d59d1e8STrond Myklebust  * later be created using rpc_mkpipe().
10497d59d1e8STrond Myklebust  */
rpc_create_client_dir(struct dentry * dentry,const char * name,struct rpc_clnt * rpc_client)105023ac6581STrond Myklebust struct dentry *rpc_create_client_dir(struct dentry *dentry,
1051a95e691fSAl Viro 				   const char *name,
10527d59d1e8STrond Myklebust 				   struct rpc_clnt *rpc_client)
10537d59d1e8STrond Myklebust {
10546739ffb7STrond Myklebust 	struct dentry *ret;
10556739ffb7STrond Myklebust 
1056d6444062SJoe Perches 	ret = rpc_mkdir_populate(dentry, name, 0555, NULL,
1057e57aed77STrond Myklebust 				 rpc_clntdir_populate, rpc_client);
10586739ffb7STrond Myklebust 	if (!IS_ERR(ret)) {
10596739ffb7STrond Myklebust 		rpc_client->cl_pipedir_objects.pdh_dentry = ret;
10606739ffb7STrond Myklebust 		rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
10616739ffb7STrond Myklebust 	}
10626739ffb7STrond Myklebust 	return ret;
1063e57aed77STrond Myklebust }
1064e57aed77STrond Myklebust 
1065e57aed77STrond Myklebust /**
1066e57aed77STrond Myklebust  * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
10676739ffb7STrond Myklebust  * @rpc_client: rpc_client for the pipe
1068e57aed77STrond Myklebust  */
rpc_remove_client_dir(struct rpc_clnt * rpc_client)1069c36dcfe1STrond Myklebust int rpc_remove_client_dir(struct rpc_clnt *rpc_client)
1070e57aed77STrond Myklebust {
1071c36dcfe1STrond Myklebust 	struct dentry *dentry = rpc_client->cl_pipedir_objects.pdh_dentry;
1072c36dcfe1STrond Myklebust 
1073c36dcfe1STrond Myklebust 	if (dentry == NULL)
1074c36dcfe1STrond Myklebust 		return 0;
10756739ffb7STrond Myklebust 	rpc_destroy_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
10766739ffb7STrond Myklebust 	rpc_client->cl_pipedir_objects.pdh_dentry = NULL;
1077e57aed77STrond Myklebust 	return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate);
10787d59d1e8STrond Myklebust }
10797d59d1e8STrond Myklebust 
10808854e82dSTrond Myklebust static const struct rpc_filelist cache_pipefs_files[3] = {
10818854e82dSTrond Myklebust 	[0] = {
10828854e82dSTrond Myklebust 		.name = "channel",
10838854e82dSTrond Myklebust 		.i_fop = &cache_file_operations_pipefs,
1084d6444062SJoe Perches 		.mode = S_IFREG | 0600,
10858854e82dSTrond Myklebust 	},
10868854e82dSTrond Myklebust 	[1] = {
10878854e82dSTrond Myklebust 		.name = "content",
10888854e82dSTrond Myklebust 		.i_fop = &content_file_operations_pipefs,
1089d6444062SJoe Perches 		.mode = S_IFREG | 0400,
10908854e82dSTrond Myklebust 	},
10918854e82dSTrond Myklebust 	[2] = {
10928854e82dSTrond Myklebust 		.name = "flush",
10938854e82dSTrond Myklebust 		.i_fop = &cache_flush_operations_pipefs,
1094d6444062SJoe Perches 		.mode = S_IFREG | 0600,
10958854e82dSTrond Myklebust 	},
10968854e82dSTrond Myklebust };
10978854e82dSTrond Myklebust 
rpc_cachedir_populate(struct dentry * dentry,void * private)10988854e82dSTrond Myklebust static int rpc_cachedir_populate(struct dentry *dentry, void *private)
10998854e82dSTrond Myklebust {
11008854e82dSTrond Myklebust 	return rpc_populate(dentry,
11018854e82dSTrond Myklebust 			    cache_pipefs_files, 0, 3,
11028854e82dSTrond Myklebust 			    private);
11038854e82dSTrond Myklebust }
11048854e82dSTrond Myklebust 
rpc_cachedir_depopulate(struct dentry * dentry)11058854e82dSTrond Myklebust static void rpc_cachedir_depopulate(struct dentry *dentry)
11068854e82dSTrond Myklebust {
11078854e82dSTrond Myklebust 	rpc_depopulate(dentry, cache_pipefs_files, 0, 3);
11088854e82dSTrond Myklebust }
11098854e82dSTrond Myklebust 
rpc_create_cache_dir(struct dentry * parent,const char * name,umode_t umode,struct cache_detail * cd)1110a95e691fSAl Viro struct dentry *rpc_create_cache_dir(struct dentry *parent, const char *name,
111164f1426fSAl Viro 				    umode_t umode, struct cache_detail *cd)
11128854e82dSTrond Myklebust {
11138854e82dSTrond Myklebust 	return rpc_mkdir_populate(parent, name, umode, NULL,
11148854e82dSTrond Myklebust 			rpc_cachedir_populate, cd);
11158854e82dSTrond Myklebust }
11168854e82dSTrond Myklebust 
rpc_remove_cache_dir(struct dentry * dentry)11178854e82dSTrond Myklebust void rpc_remove_cache_dir(struct dentry *dentry)
11188854e82dSTrond Myklebust {
11198854e82dSTrond Myklebust 	rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate);
11208854e82dSTrond Myklebust }
11218854e82dSTrond Myklebust 
11221da177e4SLinus Torvalds /*
11231da177e4SLinus Torvalds  * populate the filesystem
11241da177e4SLinus Torvalds  */
1125b87221deSAlexey Dobriyan static const struct super_operations s_ops = {
11261da177e4SLinus Torvalds 	.alloc_inode	= rpc_alloc_inode,
1127bef252faSAl Viro 	.free_inode	= rpc_free_inode,
11281da177e4SLinus Torvalds 	.statfs		= simple_statfs,
11291da177e4SLinus Torvalds };
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds #define RPCAUTH_GSSMAGIC 0x67596969
11321da177e4SLinus Torvalds 
1133bb156749STrond Myklebust /*
1134bb156749STrond Myklebust  * We have a single directory with 1 node in it.
1135bb156749STrond Myklebust  */
1136bb156749STrond Myklebust enum {
1137bb156749STrond Myklebust 	RPCAUTH_lockd,
1138bb156749STrond Myklebust 	RPCAUTH_mount,
1139bb156749STrond Myklebust 	RPCAUTH_nfs,
1140bb156749STrond Myklebust 	RPCAUTH_portmap,
1141bb156749STrond Myklebust 	RPCAUTH_statd,
1142bb156749STrond Myklebust 	RPCAUTH_nfsd4_cb,
1143e571cbf1STrond Myklebust 	RPCAUTH_cache,
1144b3537c35SJeff Layton 	RPCAUTH_nfsd,
11454b9a445eSJeff Layton 	RPCAUTH_gssd,
1146bb156749STrond Myklebust 	RPCAUTH_RootEOF
1147bb156749STrond Myklebust };
1148bb156749STrond Myklebust 
1149bb156749STrond Myklebust static const struct rpc_filelist files[] = {
1150bb156749STrond Myklebust 	[RPCAUTH_lockd] = {
1151bb156749STrond Myklebust 		.name = "lockd",
1152d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1153bb156749STrond Myklebust 	},
1154bb156749STrond Myklebust 	[RPCAUTH_mount] = {
1155bb156749STrond Myklebust 		.name = "mount",
1156d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1157bb156749STrond Myklebust 	},
1158bb156749STrond Myklebust 	[RPCAUTH_nfs] = {
1159bb156749STrond Myklebust 		.name = "nfs",
1160d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1161bb156749STrond Myklebust 	},
1162bb156749STrond Myklebust 	[RPCAUTH_portmap] = {
1163bb156749STrond Myklebust 		.name = "portmap",
1164d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1165bb156749STrond Myklebust 	},
1166bb156749STrond Myklebust 	[RPCAUTH_statd] = {
1167bb156749STrond Myklebust 		.name = "statd",
1168d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1169bb156749STrond Myklebust 	},
1170bb156749STrond Myklebust 	[RPCAUTH_nfsd4_cb] = {
1171bb156749STrond Myklebust 		.name = "nfsd4_cb",
1172d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1173bb156749STrond Myklebust 	},
1174e571cbf1STrond Myklebust 	[RPCAUTH_cache] = {
1175e571cbf1STrond Myklebust 		.name = "cache",
1176d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1177e571cbf1STrond Myklebust 	},
1178b3537c35SJeff Layton 	[RPCAUTH_nfsd] = {
1179b3537c35SJeff Layton 		.name = "nfsd",
1180d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
1181b3537c35SJeff Layton 	},
11824b9a445eSJeff Layton 	[RPCAUTH_gssd] = {
11834b9a445eSJeff Layton 		.name = "gssd",
1184d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
11854b9a445eSJeff Layton 	},
1186bb156749STrond Myklebust };
1187bb156749STrond Myklebust 
1188432eb1a5SStanislav Kinsbursky /*
1189432eb1a5SStanislav Kinsbursky  * This call can be used only in RPC pipefs mount notification hooks.
1190432eb1a5SStanislav Kinsbursky  */
rpc_d_lookup_sb(const struct super_block * sb,const unsigned char * dir_name)1191432eb1a5SStanislav Kinsbursky struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
1192432eb1a5SStanislav Kinsbursky 			       const unsigned char *dir_name)
1193432eb1a5SStanislav Kinsbursky {
119426fe5750SLinus Torvalds 	struct qstr dir = QSTR_INIT(dir_name, strlen(dir_name));
1195d3db90b0SAl Viro 	return d_hash_and_lookup(sb->s_root, &dir);
1196432eb1a5SStanislav Kinsbursky }
1197432eb1a5SStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
1198432eb1a5SStanislav Kinsbursky 
rpc_pipefs_init_net(struct net * net)11994b9a445eSJeff Layton int rpc_pipefs_init_net(struct net *net)
1200c21a588fSStanislav Kinsbursky {
1201c21a588fSStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1202c21a588fSStanislav Kinsbursky 
12034b9a445eSJeff Layton 	sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0);
12044b9a445eSJeff Layton 	if (IS_ERR(sn->gssd_dummy))
12054b9a445eSJeff Layton 		return PTR_ERR(sn->gssd_dummy);
12064b9a445eSJeff Layton 
1207c21a588fSStanislav Kinsbursky 	mutex_init(&sn->pipefs_sb_lock);
12082aed8b47STrond Myklebust 	sn->pipe_version = -1;
12094b9a445eSJeff Layton 	return 0;
12104b9a445eSJeff Layton }
12114b9a445eSJeff Layton 
rpc_pipefs_exit_net(struct net * net)12124b9a445eSJeff Layton void rpc_pipefs_exit_net(struct net *net)
12134b9a445eSJeff Layton {
12144b9a445eSJeff Layton 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
12154b9a445eSJeff Layton 
12164b9a445eSJeff Layton 	rpc_destroy_pipe_data(sn->gssd_dummy);
1217c21a588fSStanislav Kinsbursky }
1218c21a588fSStanislav Kinsbursky 
1219c21a588fSStanislav Kinsbursky /*
1220c21a588fSStanislav Kinsbursky  * This call will be used for per network namespace operations calls.
1221c21a588fSStanislav Kinsbursky  * Note: Function will be returned with pipefs_sb_lock taken if superblock was
1222c21a588fSStanislav Kinsbursky  * found. This lock have to be released by rpc_put_sb_net() when all operations
1223c21a588fSStanislav Kinsbursky  * will be completed.
1224c21a588fSStanislav Kinsbursky  */
rpc_get_sb_net(const struct net * net)1225c21a588fSStanislav Kinsbursky struct super_block *rpc_get_sb_net(const struct net *net)
1226c21a588fSStanislav Kinsbursky {
1227c21a588fSStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1228c21a588fSStanislav Kinsbursky 
1229c21a588fSStanislav Kinsbursky 	mutex_lock(&sn->pipefs_sb_lock);
1230c21a588fSStanislav Kinsbursky 	if (sn->pipefs_sb)
1231c21a588fSStanislav Kinsbursky 		return sn->pipefs_sb;
1232c21a588fSStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1233c21a588fSStanislav Kinsbursky 	return NULL;
1234c21a588fSStanislav Kinsbursky }
1235c21a588fSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_get_sb_net);
1236c21a588fSStanislav Kinsbursky 
rpc_put_sb_net(const struct net * net)1237c21a588fSStanislav Kinsbursky void rpc_put_sb_net(const struct net *net)
1238c21a588fSStanislav Kinsbursky {
1239c21a588fSStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1240c21a588fSStanislav Kinsbursky 
1241749386e9SWeston Andros Adamson 	WARN_ON(sn->pipefs_sb == NULL);
1242c21a588fSStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1243c21a588fSStanislav Kinsbursky }
1244c21a588fSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_put_sb_net);
1245c21a588fSStanislav Kinsbursky 
12464b9a445eSJeff Layton static const struct rpc_filelist gssd_dummy_clnt_dir[] = {
12474b9a445eSJeff Layton 	[0] = {
12484b9a445eSJeff Layton 		.name = "clntXX",
1249d6444062SJoe Perches 		.mode = S_IFDIR | 0555,
12504b9a445eSJeff Layton 	},
12514b9a445eSJeff Layton };
12524b9a445eSJeff Layton 
12534b9a445eSJeff Layton static ssize_t
dummy_downcall(struct file * filp,const char __user * src,size_t len)12544b9a445eSJeff Layton dummy_downcall(struct file *filp, const char __user *src, size_t len)
12554b9a445eSJeff Layton {
12564b9a445eSJeff Layton 	return -EINVAL;
12574b9a445eSJeff Layton }
12584b9a445eSJeff Layton 
12594b9a445eSJeff Layton static const struct rpc_pipe_ops gssd_dummy_pipe_ops = {
12604b9a445eSJeff Layton 	.upcall		= rpc_pipe_generic_upcall,
12614b9a445eSJeff Layton 	.downcall	= dummy_downcall,
12624b9a445eSJeff Layton };
12634b9a445eSJeff Layton 
1264e2f0c83aSJeff Layton /*
1265e2f0c83aSJeff Layton  * Here we present a bogus "info" file to keep rpc.gssd happy. We don't expect
1266e2f0c83aSJeff Layton  * that it will ever use this info to handle an upcall, but rpc.gssd expects
1267e2f0c83aSJeff Layton  * that this file will be there and have a certain format.
1268e2f0c83aSJeff Layton  */
1269e2f0c83aSJeff Layton static int
rpc_dummy_info_show(struct seq_file * m,void * v)1270260f71efSYangtao Li rpc_dummy_info_show(struct seq_file *m, void *v)
1271e2f0c83aSJeff Layton {
1272e2f0c83aSJeff Layton 	seq_printf(m, "RPC server: %s\n", utsname()->nodename);
1273e2f0c83aSJeff Layton 	seq_printf(m, "service: foo (1) version 0\n");
1274e2f0c83aSJeff Layton 	seq_printf(m, "address: 127.0.0.1\n");
1275e2f0c83aSJeff Layton 	seq_printf(m, "protocol: tcp\n");
1276e2f0c83aSJeff Layton 	seq_printf(m, "port: 0\n");
1277e2f0c83aSJeff Layton 	return 0;
1278e2f0c83aSJeff Layton }
1279260f71efSYangtao Li DEFINE_SHOW_ATTRIBUTE(rpc_dummy_info);
1280e2f0c83aSJeff Layton 
1281e2f0c83aSJeff Layton static const struct rpc_filelist gssd_dummy_info_file[] = {
1282e2f0c83aSJeff Layton 	[0] = {
1283e2f0c83aSJeff Layton 		.name = "info",
1284260f71efSYangtao Li 		.i_fop = &rpc_dummy_info_fops,
1285d6444062SJoe Perches 		.mode = S_IFREG | 0400,
1286e2f0c83aSJeff Layton 	},
1287e2f0c83aSJeff Layton };
1288e2f0c83aSJeff Layton 
12894b9a445eSJeff Layton /**
12904b9a445eSJeff Layton  * rpc_gssd_dummy_populate - create a dummy gssd pipe
12914b9a445eSJeff Layton  * @root:	root of the rpc_pipefs filesystem
12924b9a445eSJeff Layton  * @pipe_data:	pipe data created when netns is initialized
12934b9a445eSJeff Layton  *
12944b9a445eSJeff Layton  * Create a dummy set of directories and a pipe that gssd can hold open to
12954b9a445eSJeff Layton  * indicate that it is up and running.
12964b9a445eSJeff Layton  */
12974b9a445eSJeff Layton static struct dentry *
rpc_gssd_dummy_populate(struct dentry * root,struct rpc_pipe * pipe_data)12984b9a445eSJeff Layton rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
12994b9a445eSJeff Layton {
13004b9a445eSJeff Layton 	int ret = 0;
13014b9a445eSJeff Layton 	struct dentry *gssd_dentry;
13024b9a445eSJeff Layton 	struct dentry *clnt_dentry = NULL;
13034b9a445eSJeff Layton 	struct dentry *pipe_dentry = NULL;
13044b9a445eSJeff Layton 	struct qstr q = QSTR_INIT(files[RPCAUTH_gssd].name,
13054b9a445eSJeff Layton 				  strlen(files[RPCAUTH_gssd].name));
13064b9a445eSJeff Layton 
13074b9a445eSJeff Layton 	/* We should never get this far if "gssd" doesn't exist */
13084b9a445eSJeff Layton 	gssd_dentry = d_hash_and_lookup(root, &q);
13094b9a445eSJeff Layton 	if (!gssd_dentry)
13104b9a445eSJeff Layton 		return ERR_PTR(-ENOENT);
13114b9a445eSJeff Layton 
13124b9a445eSJeff Layton 	ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL);
13134b9a445eSJeff Layton 	if (ret) {
13144b9a445eSJeff Layton 		pipe_dentry = ERR_PTR(ret);
13154b9a445eSJeff Layton 		goto out;
13164b9a445eSJeff Layton 	}
13174b9a445eSJeff Layton 
13184b9a445eSJeff Layton 	q.name = gssd_dummy_clnt_dir[0].name;
13194b9a445eSJeff Layton 	q.len = strlen(gssd_dummy_clnt_dir[0].name);
13204b9a445eSJeff Layton 	clnt_dentry = d_hash_and_lookup(gssd_dentry, &q);
13214b9a445eSJeff Layton 	if (!clnt_dentry) {
1322b7ade381SVasily Averin 		__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
13234b9a445eSJeff Layton 		pipe_dentry = ERR_PTR(-ENOENT);
13244b9a445eSJeff Layton 		goto out;
13254b9a445eSJeff Layton 	}
13264b9a445eSJeff Layton 
1327e2f0c83aSJeff Layton 	ret = rpc_populate(clnt_dentry, gssd_dummy_info_file, 0, 1, NULL);
1328e2f0c83aSJeff Layton 	if (ret) {
13293396f92fSJeff Layton 		__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
1330e2f0c83aSJeff Layton 		pipe_dentry = ERR_PTR(ret);
1331e2f0c83aSJeff Layton 		goto out;
1332e2f0c83aSJeff Layton 	}
1333e2f0c83aSJeff Layton 
1334e2f0c83aSJeff Layton 	pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data);
1335e2f0c83aSJeff Layton 	if (IS_ERR(pipe_dentry)) {
1336e2f0c83aSJeff Layton 		__rpc_depopulate(clnt_dentry, gssd_dummy_info_file, 0, 1);
1337e2f0c83aSJeff Layton 		__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
1338e2f0c83aSJeff Layton 	}
13394b9a445eSJeff Layton out:
13404b9a445eSJeff Layton 	dput(clnt_dentry);
13414b9a445eSJeff Layton 	dput(gssd_dentry);
13424b9a445eSJeff Layton 	return pipe_dentry;
13434b9a445eSJeff Layton }
13444b9a445eSJeff Layton 
134523e66ba9SJeff Layton static void
rpc_gssd_dummy_depopulate(struct dentry * pipe_dentry)134623e66ba9SJeff Layton rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry)
134723e66ba9SJeff Layton {
134823e66ba9SJeff Layton 	struct dentry *clnt_dir = pipe_dentry->d_parent;
134923e66ba9SJeff Layton 	struct dentry *gssd_dir = clnt_dir->d_parent;
135023e66ba9SJeff Layton 
13514a3877c4SAl Viro 	dget(pipe_dentry);
1352c5ef6035SDavid Howells 	__rpc_rmpipe(d_inode(clnt_dir), pipe_dentry);
135323e66ba9SJeff Layton 	__rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1);
135423e66ba9SJeff Layton 	__rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1);
135523e66ba9SJeff Layton 	dput(pipe_dentry);
135623e66ba9SJeff Layton }
135723e66ba9SJeff Layton 
13581da177e4SLinus Torvalds static int
rpc_fill_super(struct super_block * sb,struct fs_context * fc)1359b9662f31SDavid Howells rpc_fill_super(struct super_block *sb, struct fs_context *fc)
13601da177e4SLinus Torvalds {
13611da177e4SLinus Torvalds 	struct inode *inode;
13624b9a445eSJeff Layton 	struct dentry *root, *gssd_dentry;
1363b9662f31SDavid Howells 	struct net *net = sb->s_fs_info;
136490c4e829SStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
13652d00131aSStanislav Kinsbursky 	int err;
13661da177e4SLinus Torvalds 
136709cbfeafSKirill A. Shutemov 	sb->s_blocksize = PAGE_SIZE;
136809cbfeafSKirill A. Shutemov 	sb->s_blocksize_bits = PAGE_SHIFT;
13691da177e4SLinus Torvalds 	sb->s_magic = RPCAUTH_GSSMAGIC;
13701da177e4SLinus Torvalds 	sb->s_op = &s_ops;
1371b26d4cd3SAl Viro 	sb->s_d_op = &simple_dentry_operations;
13721da177e4SLinus Torvalds 	sb->s_time_gran = 1;
13731da177e4SLinus Torvalds 
1374d6444062SJoe Perches 	inode = rpc_get_inode(sb, S_IFDIR | 0555);
137548fde701SAl Viro 	sb->s_root = root = d_make_root(inode);
137648fde701SAl Viro 	if (!root)
13771da177e4SLinus Torvalds 		return -ENOMEM;
1378ac6feceeSTrond Myklebust 	if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
13791da177e4SLinus Torvalds 		return -ENOMEM;
13804b9a445eSJeff Layton 
13814b9a445eSJeff Layton 	gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy);
13824b9a445eSJeff Layton 	if (IS_ERR(gssd_dentry)) {
13834b9a445eSJeff Layton 		__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
13844b9a445eSJeff Layton 		return PTR_ERR(gssd_dentry);
13854b9a445eSJeff Layton 	}
13864b9a445eSJeff Layton 
13876c67a3e4SVasily Averin 	dprintk("RPC:       sending pipefs MOUNT notification for net %x%s\n",
13886c67a3e4SVasily Averin 		net->ns.inum, NET_NAME(net));
138938481605SStanislav Kinsbursky 	mutex_lock(&sn->pipefs_sb_lock);
139037629b57SStanislav Kinsbursky 	sn->pipefs_sb = sb;
13912d00131aSStanislav Kinsbursky 	err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
13922d00131aSStanislav Kinsbursky 					   RPC_PIPEFS_MOUNT,
13932d00131aSStanislav Kinsbursky 					   sb);
13942d00131aSStanislav Kinsbursky 	if (err)
13952d00131aSStanislav Kinsbursky 		goto err_depopulate;
139638481605SStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1397fc7bed8cSAl Viro 	return 0;
13982d00131aSStanislav Kinsbursky 
13992d00131aSStanislav Kinsbursky err_depopulate:
140023e66ba9SJeff Layton 	rpc_gssd_dummy_depopulate(gssd_dentry);
14012d00131aSStanislav Kinsbursky 	blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
14022d00131aSStanislav Kinsbursky 					   RPC_PIPEFS_UMOUNT,
14032d00131aSStanislav Kinsbursky 					   sb);
140437629b57SStanislav Kinsbursky 	sn->pipefs_sb = NULL;
14052d00131aSStanislav Kinsbursky 	__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
140638481605SStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
14072d00131aSStanislav Kinsbursky 	return err;
14081da177e4SLinus Torvalds }
14091da177e4SLinus Torvalds 
141089f84243SJeff Layton bool
gssd_running(struct net * net)141189f84243SJeff Layton gssd_running(struct net *net)
141289f84243SJeff Layton {
141389f84243SJeff Layton 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
141489f84243SJeff Layton 	struct rpc_pipe *pipe = sn->gssd_dummy;
141589f84243SJeff Layton 
141689f84243SJeff Layton 	return pipe->nreaders || pipe->nwriters;
141789f84243SJeff Layton }
141889f84243SJeff Layton EXPORT_SYMBOL_GPL(gssd_running);
141989f84243SJeff Layton 
rpc_fs_get_tree(struct fs_context * fc)1420b9662f31SDavid Howells static int rpc_fs_get_tree(struct fs_context *fc)
14211da177e4SLinus Torvalds {
1422533770ccSAl Viro 	return get_tree_keyed(fc, rpc_fill_super, get_net(fc->net_ns));
1423b9662f31SDavid Howells }
1424b9662f31SDavid Howells 
rpc_fs_free_fc(struct fs_context * fc)1425b9662f31SDavid Howells static void rpc_fs_free_fc(struct fs_context *fc)
1426b9662f31SDavid Howells {
1427b9662f31SDavid Howells 	if (fc->s_fs_info)
1428b9662f31SDavid Howells 		put_net(fc->s_fs_info);
1429b9662f31SDavid Howells }
1430b9662f31SDavid Howells 
1431b9662f31SDavid Howells static const struct fs_context_operations rpc_fs_context_ops = {
1432b9662f31SDavid Howells 	.free		= rpc_fs_free_fc,
1433b9662f31SDavid Howells 	.get_tree	= rpc_fs_get_tree,
1434b9662f31SDavid Howells };
1435b9662f31SDavid Howells 
rpc_init_fs_context(struct fs_context * fc)1436b9662f31SDavid Howells static int rpc_init_fs_context(struct fs_context *fc)
1437b9662f31SDavid Howells {
1438b9662f31SDavid Howells 	put_user_ns(fc->user_ns);
1439b9662f31SDavid Howells 	fc->user_ns = get_user_ns(fc->net_ns->user_ns);
1440b9662f31SDavid Howells 	fc->ops = &rpc_fs_context_ops;
1441b9662f31SDavid Howells 	return 0;
14421da177e4SLinus Torvalds }
14431da177e4SLinus Torvalds 
rpc_kill_sb(struct super_block * sb)144409acfea5STrond Myklebust static void rpc_kill_sb(struct super_block *sb)
1445021c68deSStanislav Kinsbursky {
1446021c68deSStanislav Kinsbursky 	struct net *net = sb->s_fs_info;
144790c4e829SStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1448021c68deSStanislav Kinsbursky 
1449c21a588fSStanislav Kinsbursky 	mutex_lock(&sn->pipefs_sb_lock);
1450642fe4d0STrond Myklebust 	if (sn->pipefs_sb != sb) {
1451642fe4d0STrond Myklebust 		mutex_unlock(&sn->pipefs_sb_lock);
1452642fe4d0STrond Myklebust 		goto out;
1453642fe4d0STrond Myklebust 	}
145490c4e829SStanislav Kinsbursky 	sn->pipefs_sb = NULL;
14556c67a3e4SVasily Averin 	dprintk("RPC:       sending pipefs UMOUNT notification for net %x%s\n",
14566c67a3e4SVasily Averin 		net->ns.inum, NET_NAME(net));
14572d00131aSStanislav Kinsbursky 	blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
14582d00131aSStanislav Kinsbursky 					   RPC_PIPEFS_UMOUNT,
14592d00131aSStanislav Kinsbursky 					   sb);
1460adb6fa7fSStanislav Kinsbursky 	mutex_unlock(&sn->pipefs_sb_lock);
1461642fe4d0STrond Myklebust out:
1462021c68deSStanislav Kinsbursky 	kill_litter_super(sb);
1463d91ee87dSEric W. Biederman 	put_net(net);
14641da177e4SLinus Torvalds }
14651da177e4SLinus Torvalds 
14661da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type = {
14671da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
14681da177e4SLinus Torvalds 	.name		= "rpc_pipefs",
1469b9662f31SDavid Howells 	.init_fs_context = rpc_init_fs_context,
1470021c68deSStanislav Kinsbursky 	.kill_sb	= rpc_kill_sb,
14711da177e4SLinus Torvalds };
14727f78e035SEric W. Biederman MODULE_ALIAS_FS("rpc_pipefs");
1473fa7614ddSEric W. Biederman MODULE_ALIAS("rpc_pipefs");
14741da177e4SLinus Torvalds 
14751da177e4SLinus Torvalds static void
init_once(void * foo)147651cc5068SAlexey Dobriyan init_once(void *foo)
14771da177e4SLinus Torvalds {
14781da177e4SLinus Torvalds 	struct rpc_inode *rpci = (struct rpc_inode *) foo;
14791da177e4SLinus Torvalds 
14801da177e4SLinus Torvalds 	inode_init_once(&rpci->vfs_inode);
14811da177e4SLinus Torvalds 	rpci->private = NULL;
1482ba9e0975SStanislav Kinsbursky 	rpci->pipe = NULL;
14831da177e4SLinus Torvalds 	init_waitqueue_head(&rpci->waitq);
14841da177e4SLinus Torvalds }
14851da177e4SLinus Torvalds 
register_rpc_pipefs(void)14861da177e4SLinus Torvalds int register_rpc_pipefs(void)
14871da177e4SLinus Torvalds {
14885bd5f581SAkinobu Mita 	int err;
14895bd5f581SAkinobu Mita 
14901da177e4SLinus Torvalds 	rpc_inode_cachep = kmem_cache_create("rpc_inode_cache",
14911da177e4SLinus Torvalds 				sizeof(struct rpc_inode),
1492fffb60f9SPaul Jackson 				0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
14935d097056SVladimir Davydov 						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
149420c2df83SPaul Mundt 				init_once);
14951da177e4SLinus Torvalds 	if (!rpc_inode_cachep)
14961da177e4SLinus Torvalds 		return -ENOMEM;
149780df9d20SStanislav Kinsbursky 	err = rpc_clients_notifier_register();
149880df9d20SStanislav Kinsbursky 	if (err)
149980df9d20SStanislav Kinsbursky 		goto err_notifier;
15005bd5f581SAkinobu Mita 	err = register_filesystem(&rpc_pipe_fs_type);
150180df9d20SStanislav Kinsbursky 	if (err)
150280df9d20SStanislav Kinsbursky 		goto err_register;
150380df9d20SStanislav Kinsbursky 	return 0;
150480df9d20SStanislav Kinsbursky 
150580df9d20SStanislav Kinsbursky err_register:
150680df9d20SStanislav Kinsbursky 	rpc_clients_notifier_unregister();
150780df9d20SStanislav Kinsbursky err_notifier:
15085bd5f581SAkinobu Mita 	kmem_cache_destroy(rpc_inode_cachep);
15095bd5f581SAkinobu Mita 	return err;
15105bd5f581SAkinobu Mita }
15115bd5f581SAkinobu Mita 
unregister_rpc_pipefs(void)15121da177e4SLinus Torvalds void unregister_rpc_pipefs(void)
15131da177e4SLinus Torvalds {
151480df9d20SStanislav Kinsbursky 	rpc_clients_notifier_unregister();
15151da177e4SLinus Torvalds 	unregister_filesystem(&rpc_pipe_fs_type);
15164a400f0dSDan Aloni 	kmem_cache_destroy(rpc_inode_cachep);
15171da177e4SLinus Torvalds }
1518