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