1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * net/sunrpc/rpc_pipe.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Userland/kernel interface for rpcauth_gss. 61da177e4SLinus Torvalds * Code shamelessly plagiarized from fs/nfsd/nfsctl.c 7d51fe1beSRolf Eike Beer * and fs/sysfs/inode.c 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no> 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/slab.h> 141da177e4SLinus Torvalds #include <linux/string.h> 151da177e4SLinus Torvalds #include <linux/pagemap.h> 161da177e4SLinus Torvalds #include <linux/mount.h> 17b9662f31SDavid Howells #include <linux/fs_context.h> 181da177e4SLinus Torvalds #include <linux/namei.h> 1950e437d5STrond Myklebust #include <linux/fsnotify.h> 201da177e4SLinus Torvalds #include <linux/kernel.h> 212446ab60STrond Myklebust #include <linux/rcupdate.h> 22e2f0c83aSJeff Layton #include <linux/utsname.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #include <asm/ioctls.h> 251da177e4SLinus Torvalds #include <linux/poll.h> 261da177e4SLinus Torvalds #include <linux/wait.h> 271da177e4SLinus Torvalds #include <linux/seq_file.h> 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 301da177e4SLinus Torvalds #include <linux/workqueue.h> 311da177e4SLinus Torvalds #include <linux/sunrpc/rpc_pipe_fs.h> 328854e82dSTrond Myklebust #include <linux/sunrpc/cache.h> 33021c68deSStanislav Kinsbursky #include <linux/nsproxy.h> 342d00131aSStanislav Kinsbursky #include <linux/notifier.h> 351da177e4SLinus Torvalds 36021c68deSStanislav Kinsbursky #include "netns.h" 372d00131aSStanislav Kinsbursky #include "sunrpc.h" 381da177e4SLinus Torvalds 39efc46bf2SStanislav Kinsbursky #define RPCDBG_FACILITY RPCDBG_DEBUG 40efc46bf2SStanislav Kinsbursky 41efc46bf2SStanislav Kinsbursky #define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type; 444b9a445eSJeff Layton static const struct rpc_pipe_ops gssd_dummy_pipe_ops; 451da177e4SLinus Torvalds 46e18b890bSChristoph Lameter static struct kmem_cache *rpc_inode_cachep __read_mostly; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds #define RPC_UPCALL_TIMEOUT (30*HZ) 491da177e4SLinus Torvalds 502d00131aSStanislav Kinsbursky static BLOCKING_NOTIFIER_HEAD(rpc_pipefs_notifier_list); 512d00131aSStanislav Kinsbursky 522d00131aSStanislav Kinsbursky int rpc_pipefs_notifier_register(struct notifier_block *nb) 532d00131aSStanislav Kinsbursky { 54260a2679SXiaoming Ni return blocking_notifier_chain_register(&rpc_pipefs_notifier_list, nb); 552d00131aSStanislav Kinsbursky } 562d00131aSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_register); 572d00131aSStanislav Kinsbursky 582d00131aSStanislav Kinsbursky void rpc_pipefs_notifier_unregister(struct notifier_block *nb) 592d00131aSStanislav Kinsbursky { 602d00131aSStanislav Kinsbursky blocking_notifier_chain_unregister(&rpc_pipefs_notifier_list, nb); 612d00131aSStanislav Kinsbursky } 622d00131aSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister); 632d00131aSStanislav Kinsbursky 64591ad7feSStanislav Kinsbursky static void rpc_purge_list(wait_queue_head_t *waitq, struct list_head *head, 659842ef35STrond Myklebust void (*destroy_msg)(struct rpc_pipe_msg *), int err) 66b3eb67a2STrond Myklebust { 67b3eb67a2STrond Myklebust struct rpc_pipe_msg *msg; 68b3eb67a2STrond Myklebust 699842ef35STrond Myklebust if (list_empty(head)) 709842ef35STrond Myklebust return; 719842ef35STrond Myklebust do { 72b3eb67a2STrond Myklebust msg = list_entry(head->next, struct rpc_pipe_msg, list); 735a67657aSTrond Myklebust list_del_init(&msg->list); 74b3eb67a2STrond Myklebust msg->errno = err; 75b3eb67a2STrond Myklebust destroy_msg(msg); 769842ef35STrond Myklebust } while (!list_empty(head)); 7792123e06SJeff Layton 7892123e06SJeff Layton if (waitq) 79591ad7feSStanislav Kinsbursky wake_up(waitq); 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds static void 8365f27f38SDavid Howells rpc_timeout_upcall_queue(struct work_struct *work) 841da177e4SLinus Torvalds { 859842ef35STrond Myklebust LIST_HEAD(free_list); 86ba9e0975SStanislav Kinsbursky struct rpc_pipe *pipe = 87ba9e0975SStanislav Kinsbursky container_of(work, struct rpc_pipe, queue_timeout.work); 889842ef35STrond Myklebust void (*destroy_msg)(struct rpc_pipe_msg *); 89591ad7feSStanislav Kinsbursky struct dentry *dentry; 901da177e4SLinus Torvalds 91ba9e0975SStanislav Kinsbursky spin_lock(&pipe->lock); 92ba9e0975SStanislav Kinsbursky destroy_msg = pipe->ops->destroy_msg; 93ba9e0975SStanislav Kinsbursky if (pipe->nreaders == 0) { 94ba9e0975SStanislav Kinsbursky list_splice_init(&pipe->pipe, &free_list); 95ba9e0975SStanislav Kinsbursky pipe->pipelen = 0; 969842ef35STrond Myklebust } 97591ad7feSStanislav Kinsbursky dentry = dget(pipe->dentry); 98ba9e0975SStanislav Kinsbursky spin_unlock(&pipe->lock); 99c5ef6035SDavid Howells rpc_purge_list(dentry ? &RPC_I(d_inode(dentry))->waitq : NULL, 100591ad7feSStanislav Kinsbursky &free_list, destroy_msg, -ETIMEDOUT); 101591ad7feSStanislav Kinsbursky dput(dentry); 1029842ef35STrond Myklebust } 1031da177e4SLinus Torvalds 104c1225158SPeng Tao ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg, 105c1225158SPeng Tao char __user *dst, size_t buflen) 106c1225158SPeng Tao { 107c1225158SPeng Tao char *data = (char *)msg->data + msg->copied; 108c1225158SPeng Tao size_t mlen = min(msg->len - msg->copied, buflen); 109c1225158SPeng Tao unsigned long left; 110c1225158SPeng Tao 111c1225158SPeng Tao left = copy_to_user(dst, data, mlen); 112c1225158SPeng Tao if (left == mlen) { 113c1225158SPeng Tao msg->errno = -EFAULT; 114c1225158SPeng Tao return -EFAULT; 115c1225158SPeng Tao } 116c1225158SPeng Tao 117c1225158SPeng Tao mlen -= left; 118c1225158SPeng Tao msg->copied += mlen; 119c1225158SPeng Tao msg->errno = 0; 120c1225158SPeng Tao return mlen; 121c1225158SPeng Tao } 122c1225158SPeng Tao EXPORT_SYMBOL_GPL(rpc_pipe_generic_upcall); 123c1225158SPeng Tao 12493a44a75SJ. Bruce Fields /** 1251a5778aaSBen Hutchings * rpc_queue_upcall - queue an upcall message to userspace 126bda14606SRandy Dunlap * @pipe: upcall pipe on which to queue given message 12793a44a75SJ. Bruce Fields * @msg: message to queue 12893a44a75SJ. Bruce Fields * 12993a44a75SJ. Bruce Fields * Call with an @inode created by rpc_mkpipe() to queue an upcall. 13093a44a75SJ. Bruce Fields * A userspace process may then later read the upcall by performing a 13193a44a75SJ. Bruce Fields * read on an open file for this inode. It is up to the caller to 13293a44a75SJ. Bruce Fields * initialize the fields of @msg (other than @msg->list) appropriately. 13393a44a75SJ. Bruce Fields */ 1341da177e4SLinus Torvalds int 135d706ed1fSStanislav Kinsbursky rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg) 1361da177e4SLinus Torvalds { 1376070fe6fSTrond Myklebust int res = -EPIPE; 138591ad7feSStanislav Kinsbursky struct dentry *dentry; 1391da177e4SLinus Torvalds 140d0fe13baSStanislav Kinsbursky spin_lock(&pipe->lock); 141d0fe13baSStanislav Kinsbursky if (pipe->nreaders) { 142d0fe13baSStanislav Kinsbursky list_add_tail(&msg->list, &pipe->pipe); 143d0fe13baSStanislav Kinsbursky pipe->pipelen += msg->len; 1446070fe6fSTrond Myklebust res = 0; 145d0fe13baSStanislav Kinsbursky } else if (pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) { 146d0fe13baSStanislav Kinsbursky if (list_empty(&pipe->pipe)) 14724c5d9d7STrond Myklebust queue_delayed_work(rpciod_workqueue, 148d0fe13baSStanislav Kinsbursky &pipe->queue_timeout, 1491da177e4SLinus Torvalds RPC_UPCALL_TIMEOUT); 150d0fe13baSStanislav Kinsbursky list_add_tail(&msg->list, &pipe->pipe); 151d0fe13baSStanislav Kinsbursky pipe->pipelen += msg->len; 1526070fe6fSTrond Myklebust res = 0; 1536070fe6fSTrond Myklebust } 154591ad7feSStanislav Kinsbursky dentry = dget(pipe->dentry); 155d0fe13baSStanislav Kinsbursky spin_unlock(&pipe->lock); 156591ad7feSStanislav Kinsbursky if (dentry) { 157c5ef6035SDavid Howells wake_up(&RPC_I(d_inode(dentry))->waitq); 158591ad7feSStanislav Kinsbursky dput(dentry); 159591ad7feSStanislav Kinsbursky } 1601da177e4SLinus Torvalds return res; 1611da177e4SLinus Torvalds } 162468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_queue_upcall); 1631da177e4SLinus Torvalds 1646070fe6fSTrond Myklebust static inline void 1656070fe6fSTrond Myklebust rpc_inode_setowner(struct inode *inode, void *private) 1666070fe6fSTrond Myklebust { 1676070fe6fSTrond Myklebust RPC_I(inode)->private = private; 1686070fe6fSTrond Myklebust } 1696070fe6fSTrond Myklebust 1701da177e4SLinus Torvalds static void 1711da177e4SLinus Torvalds rpc_close_pipes(struct inode *inode) 1721da177e4SLinus Torvalds { 173ba9e0975SStanislav Kinsbursky struct rpc_pipe *pipe = RPC_I(inode)->pipe; 174e712804aS\"J. Bruce Fields\ int need_release; 175ad6b1340SStanislav Kinsbursky LIST_HEAD(free_list); 1761da177e4SLinus Torvalds 1775955102cSAl Viro inode_lock(inode); 178ba9e0975SStanislav Kinsbursky spin_lock(&pipe->lock); 179ba9e0975SStanislav Kinsbursky need_release = pipe->nreaders != 0 || pipe->nwriters != 0; 180ba9e0975SStanislav Kinsbursky pipe->nreaders = 0; 181ba9e0975SStanislav Kinsbursky list_splice_init(&pipe->in_upcall, &free_list); 182ba9e0975SStanislav Kinsbursky list_splice_init(&pipe->pipe, &free_list); 183ba9e0975SStanislav Kinsbursky pipe->pipelen = 0; 184ad6b1340SStanislav Kinsbursky pipe->dentry = NULL; 185ba9e0975SStanislav Kinsbursky spin_unlock(&pipe->lock); 186591ad7feSStanislav Kinsbursky rpc_purge_list(&RPC_I(inode)->waitq, &free_list, pipe->ops->destroy_msg, -EPIPE); 187ba9e0975SStanislav Kinsbursky pipe->nwriters = 0; 188ad6b1340SStanislav Kinsbursky if (need_release && pipe->ops->release_pipe) 189ad6b1340SStanislav Kinsbursky pipe->ops->release_pipe(inode); 190ba9e0975SStanislav Kinsbursky cancel_delayed_work_sync(&pipe->queue_timeout); 1916070fe6fSTrond Myklebust rpc_inode_setowner(inode, NULL); 1922c9030eeSStanislav Kinsbursky RPC_I(inode)->pipe = NULL; 1935955102cSAl Viro inode_unlock(inode); 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds static struct inode * 1971da177e4SLinus Torvalds rpc_alloc_inode(struct super_block *sb) 1981da177e4SLinus Torvalds { 1991da177e4SLinus Torvalds struct rpc_inode *rpci; 200adcda652SHimangi Saraogi rpci = kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); 2011da177e4SLinus Torvalds if (!rpci) 2021da177e4SLinus Torvalds return NULL; 2031da177e4SLinus Torvalds return &rpci->vfs_inode; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds static void 207bef252faSAl Viro rpc_free_inode(struct inode *inode) 208fa0d7e3dSNick Piggin { 209fa0d7e3dSNick Piggin kmem_cache_free(rpc_inode_cachep, RPC_I(inode)); 210fa0d7e3dSNick Piggin } 211fa0d7e3dSNick Piggin 2121da177e4SLinus Torvalds static int 2131da177e4SLinus Torvalds rpc_pipe_open(struct inode *inode, struct file *filp) 2141da177e4SLinus Torvalds { 2152c9030eeSStanislav Kinsbursky struct rpc_pipe *pipe; 216c3810608S\"J. Bruce Fields\ int first_open; 2171da177e4SLinus Torvalds int res = -ENXIO; 2181da177e4SLinus Torvalds 2195955102cSAl Viro inode_lock(inode); 2202c9030eeSStanislav Kinsbursky pipe = RPC_I(inode)->pipe; 2212c9030eeSStanislav Kinsbursky if (pipe == NULL) 222c3810608S\"J. Bruce Fields\ goto out; 223d0fe13baSStanislav Kinsbursky first_open = pipe->nreaders == 0 && pipe->nwriters == 0; 224d0fe13baSStanislav Kinsbursky if (first_open && pipe->ops->open_pipe) { 225d0fe13baSStanislav Kinsbursky res = pipe->ops->open_pipe(inode); 226c3810608S\"J. Bruce Fields\ if (res) 227c3810608S\"J. Bruce Fields\ goto out; 228c3810608S\"J. Bruce Fields\ } 2291da177e4SLinus Torvalds if (filp->f_mode & FMODE_READ) 230d0fe13baSStanislav Kinsbursky pipe->nreaders++; 2311da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 232d0fe13baSStanislav Kinsbursky pipe->nwriters++; 2331da177e4SLinus Torvalds res = 0; 234c3810608S\"J. Bruce Fields\ out: 2355955102cSAl Viro inode_unlock(inode); 2361da177e4SLinus Torvalds return res; 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds static int 2401da177e4SLinus Torvalds rpc_pipe_release(struct inode *inode, struct file *filp) 2411da177e4SLinus Torvalds { 2422c9030eeSStanislav Kinsbursky struct rpc_pipe *pipe; 2431da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 244e712804aS\"J. Bruce Fields\ int last_close; 2451da177e4SLinus Torvalds 2465955102cSAl Viro inode_lock(inode); 2472c9030eeSStanislav Kinsbursky pipe = RPC_I(inode)->pipe; 2482c9030eeSStanislav Kinsbursky if (pipe == NULL) 2491da177e4SLinus Torvalds goto out; 250655b5bb4SJoe Perches msg = filp->private_data; 2511da177e4SLinus Torvalds if (msg != NULL) { 252ba9e0975SStanislav Kinsbursky spin_lock(&pipe->lock); 25348e49187STrond Myklebust msg->errno = -EAGAIN; 2545a67657aSTrond Myklebust list_del_init(&msg->list); 255ba9e0975SStanislav Kinsbursky spin_unlock(&pipe->lock); 256ba9e0975SStanislav Kinsbursky pipe->ops->destroy_msg(msg); 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 259ba9e0975SStanislav Kinsbursky pipe->nwriters --; 2609842ef35STrond Myklebust if (filp->f_mode & FMODE_READ) { 261ba9e0975SStanislav Kinsbursky pipe->nreaders --; 262ba9e0975SStanislav Kinsbursky if (pipe->nreaders == 0) { 2639842ef35STrond Myklebust LIST_HEAD(free_list); 264ba9e0975SStanislav Kinsbursky spin_lock(&pipe->lock); 265ba9e0975SStanislav Kinsbursky list_splice_init(&pipe->pipe, &free_list); 266ba9e0975SStanislav Kinsbursky pipe->pipelen = 0; 267ba9e0975SStanislav Kinsbursky spin_unlock(&pipe->lock); 268591ad7feSStanislav Kinsbursky rpc_purge_list(&RPC_I(inode)->waitq, &free_list, 269ba9e0975SStanislav Kinsbursky pipe->ops->destroy_msg, -EAGAIN); 2709842ef35STrond Myklebust } 2719842ef35STrond Myklebust } 272ba9e0975SStanislav Kinsbursky last_close = pipe->nwriters == 0 && pipe->nreaders == 0; 273ba9e0975SStanislav Kinsbursky if (last_close && pipe->ops->release_pipe) 274ba9e0975SStanislav Kinsbursky pipe->ops->release_pipe(inode); 2751da177e4SLinus Torvalds out: 2765955102cSAl Viro inode_unlock(inode); 2771da177e4SLinus Torvalds return 0; 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds static ssize_t 2811da177e4SLinus Torvalds rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) 2821da177e4SLinus Torvalds { 283496ad9aaSAl Viro struct inode *inode = file_inode(filp); 2842c9030eeSStanislav Kinsbursky struct rpc_pipe *pipe; 2851da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 2861da177e4SLinus Torvalds int res = 0; 2871da177e4SLinus Torvalds 2885955102cSAl Viro inode_lock(inode); 2892c9030eeSStanislav Kinsbursky pipe = RPC_I(inode)->pipe; 2902c9030eeSStanislav Kinsbursky if (pipe == NULL) { 2911da177e4SLinus Torvalds res = -EPIPE; 2921da177e4SLinus Torvalds goto out_unlock; 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds msg = filp->private_data; 2951da177e4SLinus Torvalds if (msg == NULL) { 296d0fe13baSStanislav Kinsbursky spin_lock(&pipe->lock); 297d0fe13baSStanislav Kinsbursky if (!list_empty(&pipe->pipe)) { 298d0fe13baSStanislav Kinsbursky msg = list_entry(pipe->pipe.next, 2991da177e4SLinus Torvalds struct rpc_pipe_msg, 3001da177e4SLinus Torvalds list); 301d0fe13baSStanislav Kinsbursky list_move(&msg->list, &pipe->in_upcall); 302d0fe13baSStanislav Kinsbursky pipe->pipelen -= msg->len; 3031da177e4SLinus Torvalds filp->private_data = msg; 3041da177e4SLinus Torvalds msg->copied = 0; 3051da177e4SLinus Torvalds } 306d0fe13baSStanislav Kinsbursky spin_unlock(&pipe->lock); 3071da177e4SLinus Torvalds if (msg == NULL) 3081da177e4SLinus Torvalds goto out_unlock; 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds /* NOTE: it is up to the callback to update msg->copied */ 311d0fe13baSStanislav Kinsbursky res = pipe->ops->upcall(filp, msg, buf, len); 3121da177e4SLinus Torvalds if (res < 0 || msg->len == msg->copied) { 3131da177e4SLinus Torvalds filp->private_data = NULL; 314d0fe13baSStanislav Kinsbursky spin_lock(&pipe->lock); 3155a67657aSTrond Myklebust list_del_init(&msg->list); 316d0fe13baSStanislav Kinsbursky spin_unlock(&pipe->lock); 317d0fe13baSStanislav Kinsbursky pipe->ops->destroy_msg(msg); 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds out_unlock: 3205955102cSAl Viro inode_unlock(inode); 3211da177e4SLinus Torvalds return res; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds static ssize_t 3251da177e4SLinus Torvalds rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) 3261da177e4SLinus Torvalds { 327496ad9aaSAl Viro struct inode *inode = file_inode(filp); 3281da177e4SLinus Torvalds int res; 3291da177e4SLinus Torvalds 3305955102cSAl Viro inode_lock(inode); 3311da177e4SLinus Torvalds res = -EPIPE; 3322c9030eeSStanislav Kinsbursky if (RPC_I(inode)->pipe != NULL) 3332c9030eeSStanislav Kinsbursky res = RPC_I(inode)->pipe->ops->downcall(filp, buf, len); 3345955102cSAl Viro inode_unlock(inode); 3351da177e4SLinus Torvalds return res; 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 338ade994f4SAl Viro static __poll_t 3391da177e4SLinus Torvalds rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) 3401da177e4SLinus Torvalds { 341496ad9aaSAl Viro struct inode *inode = file_inode(filp); 342591ad7feSStanislav Kinsbursky struct rpc_inode *rpci = RPC_I(inode); 343a9a08845SLinus Torvalds __poll_t mask = EPOLLOUT | EPOLLWRNORM; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds poll_wait(filp, &rpci->waitq, wait); 3461da177e4SLinus Torvalds 3475955102cSAl Viro inode_lock(inode); 348591ad7feSStanislav Kinsbursky if (rpci->pipe == NULL) 349a9a08845SLinus Torvalds mask |= EPOLLERR | EPOLLHUP; 350591ad7feSStanislav Kinsbursky else if (filp->private_data || !list_empty(&rpci->pipe->pipe)) 351a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM; 3525955102cSAl Viro inode_unlock(inode); 3531da177e4SLinus Torvalds return mask; 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds 356a6f8dbc6SArnd Bergmann static long 357a6f8dbc6SArnd Bergmann rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 3581da177e4SLinus Torvalds { 359496ad9aaSAl Viro struct inode *inode = file_inode(filp); 3602c9030eeSStanislav Kinsbursky struct rpc_pipe *pipe; 3611da177e4SLinus Torvalds int len; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds switch (cmd) { 3641da177e4SLinus Torvalds case FIONREAD: 3655955102cSAl Viro inode_lock(inode); 3662c9030eeSStanislav Kinsbursky pipe = RPC_I(inode)->pipe; 3672c9030eeSStanislav Kinsbursky if (pipe == NULL) { 3685955102cSAl Viro inode_unlock(inode); 3691da177e4SLinus Torvalds return -EPIPE; 370a6f8dbc6SArnd Bergmann } 3712c9030eeSStanislav Kinsbursky spin_lock(&pipe->lock); 372d0fe13baSStanislav Kinsbursky len = pipe->pipelen; 3731da177e4SLinus Torvalds if (filp->private_data) { 3741da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 375655b5bb4SJoe Perches msg = filp->private_data; 3761da177e4SLinus Torvalds len += msg->len - msg->copied; 3771da177e4SLinus Torvalds } 378d0fe13baSStanislav Kinsbursky spin_unlock(&pipe->lock); 3795955102cSAl Viro inode_unlock(inode); 3801da177e4SLinus Torvalds return put_user(len, (int __user *)arg); 3811da177e4SLinus Torvalds default: 3821da177e4SLinus Torvalds return -EINVAL; 3831da177e4SLinus Torvalds } 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds 386da7071d7SArjan van de Ven static const struct file_operations rpc_pipe_fops = { 3871da177e4SLinus Torvalds .owner = THIS_MODULE, 3881da177e4SLinus Torvalds .llseek = no_llseek, 3891da177e4SLinus Torvalds .read = rpc_pipe_read, 3901da177e4SLinus Torvalds .write = rpc_pipe_write, 3911da177e4SLinus Torvalds .poll = rpc_pipe_poll, 392674b604cSFrederic Weisbecker .unlocked_ioctl = rpc_pipe_ioctl, 3931da177e4SLinus Torvalds .open = rpc_pipe_open, 3941da177e4SLinus Torvalds .release = rpc_pipe_release, 3951da177e4SLinus Torvalds }; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds static int 3981da177e4SLinus Torvalds rpc_show_info(struct seq_file *m, void *v) 3991da177e4SLinus Torvalds { 4001da177e4SLinus Torvalds struct rpc_clnt *clnt = m->private; 4011da177e4SLinus Torvalds 4022446ab60STrond Myklebust rcu_read_lock(); 4034e0038b6STrond Myklebust seq_printf(m, "RPC server: %s\n", 4044e0038b6STrond Myklebust rcu_dereference(clnt->cl_xprt)->servername); 40555909f21STrond Myklebust seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_program->name, 4061da177e4SLinus Torvalds clnt->cl_prog, clnt->cl_vers); 407e7f78657SChuck Lever seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); 408e7f78657SChuck Lever seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); 409bf19aaceSJ. Bruce Fields seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); 4102446ab60STrond Myklebust rcu_read_unlock(); 4111da177e4SLinus Torvalds return 0; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds static int 4151da177e4SLinus Torvalds rpc_info_open(struct inode *inode, struct file *file) 4161da177e4SLinus Torvalds { 417006abe88STrond Myklebust struct rpc_clnt *clnt = NULL; 4181da177e4SLinus Torvalds int ret = single_open(file, rpc_show_info, NULL); 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds if (!ret) { 4211da177e4SLinus Torvalds struct seq_file *m = file->private_data; 422006abe88STrond Myklebust 423006abe88STrond Myklebust spin_lock(&file->f_path.dentry->d_lock); 424006abe88STrond Myklebust if (!d_unhashed(file->f_path.dentry)) 4251da177e4SLinus Torvalds clnt = RPC_I(inode)->private; 426*71d3d0ebSTrond 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 4391da177e4SLinus Torvalds rpc_info_release(struct inode *inode, struct file *file) 4401da177e4SLinus Torvalds { 4411da177e4SLinus Torvalds struct seq_file *m = file->private_data; 4421da177e4SLinus Torvalds struct rpc_clnt *clnt = (struct rpc_clnt *)m->private; 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds if (clnt) 4451da177e4SLinus Torvalds rpc_release_client(clnt); 4461da177e4SLinus Torvalds return single_release(inode, file); 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds 449da7071d7SArjan van de Ven static const struct file_operations rpc_info_operations = { 4501da177e4SLinus Torvalds .owner = THIS_MODULE, 4511da177e4SLinus Torvalds .open = rpc_info_open, 4521da177e4SLinus Torvalds .read = seq_read, 4531da177e4SLinus Torvalds .llseek = seq_lseek, 4541da177e4SLinus Torvalds .release = rpc_info_release, 4551da177e4SLinus Torvalds }; 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds /* 4591da177e4SLinus Torvalds * Description of fs contents. 4601da177e4SLinus Torvalds */ 4611da177e4SLinus Torvalds struct rpc_filelist { 462ac6feceeSTrond Myklebust const char *name; 46399ac48f5SArjan van de Ven const struct file_operations *i_fop; 4647364af6aSTrond Myklebust umode_t mode; 4651da177e4SLinus Torvalds }; 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds static struct inode * 4687364af6aSTrond Myklebust rpc_get_inode(struct super_block *sb, umode_t mode) 4691da177e4SLinus Torvalds { 4701da177e4SLinus Torvalds struct inode *inode = new_inode(sb); 4711da177e4SLinus Torvalds if (!inode) 4721da177e4SLinus Torvalds return NULL; 47385fe4025SChristoph Hellwig inode->i_ino = get_next_ino(); 4741da177e4SLinus Torvalds inode->i_mode = mode; 475078cd827SDeepa Dinamani inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); 4761da177e4SLinus Torvalds switch (mode & S_IFMT) { 4771da177e4SLinus Torvalds case S_IFDIR: 4781da177e4SLinus Torvalds inode->i_fop = &simple_dir_operations; 479275448ebSJeff Layton inode->i_op = &simple_dir_inode_operations; 480d8c76e6fSDave Hansen inc_nlink(inode); 48193f479d3SGustavo A. R. Silva break; 4821da177e4SLinus Torvalds default: 4831da177e4SLinus Torvalds break; 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds return inode; 4861da177e4SLinus Torvalds } 4871da177e4SLinus Torvalds 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 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 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 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 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 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 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 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); 603a35d632cSAmir Goldstein if (!ret) 604a35d632cSAmir Goldstein fsnotify_rmdir(dir, dentry); 605ac6feceeSTrond Myklebust d_delete(dentry); 606ac6feceeSTrond Myklebust dput(dentry); 607ac6feceeSTrond Myklebust return ret; 608ac6feceeSTrond Myklebust } 609ac6feceeSTrond Myklebust 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); 616a35d632cSAmir Goldstein if (!ret) 617a35d632cSAmir Goldstein fsnotify_unlink(dir, dentry); 618810d90bcSTrond Myklebust d_delete(dentry); 619810d90bcSTrond Myklebust dput(dentry); 620810d90bcSTrond Myklebust return ret; 621810d90bcSTrond Myklebust } 622810d90bcSTrond Myklebust 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 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 */ 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 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 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 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 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 */ 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 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 */ 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 */ 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 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 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 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 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 * 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 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 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 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 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 */ 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 */ 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 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 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 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 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 */ 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 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 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 */ 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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