11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * net/sunrpc/rpc_pipe.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Userland/kernel interface for rpcauth_gss. 51da177e4SLinus Torvalds * Code shamelessly plagiarized from fs/nfsd/nfsctl.c 6d51fe1beSRolf Eike Beer * and fs/sysfs/inode.c 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no> 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds #include <linux/module.h> 121da177e4SLinus Torvalds #include <linux/slab.h> 131da177e4SLinus Torvalds #include <linux/string.h> 141da177e4SLinus Torvalds #include <linux/pagemap.h> 151da177e4SLinus Torvalds #include <linux/mount.h> 161da177e4SLinus Torvalds #include <linux/namei.h> 1750e437d5STrond Myklebust #include <linux/fsnotify.h> 181da177e4SLinus Torvalds #include <linux/kernel.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds #include <asm/ioctls.h> 211da177e4SLinus Torvalds #include <linux/fs.h> 221da177e4SLinus Torvalds #include <linux/poll.h> 231da177e4SLinus Torvalds #include <linux/wait.h> 241da177e4SLinus Torvalds #include <linux/seq_file.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 271da177e4SLinus Torvalds #include <linux/workqueue.h> 281da177e4SLinus Torvalds #include <linux/sunrpc/rpc_pipe_fs.h> 298854e82dSTrond Myklebust #include <linux/sunrpc/cache.h> 30021c68deSStanislav Kinsbursky #include <linux/nsproxy.h> 312d00131aSStanislav Kinsbursky #include <linux/notifier.h> 32021c68deSStanislav Kinsbursky 33021c68deSStanislav Kinsbursky #include "netns.h" 342d00131aSStanislav Kinsbursky #include "sunrpc.h" 351da177e4SLinus Torvalds 36fc14f2feSAl Viro static struct vfsmount *rpc_mnt __read_mostly; 371da177e4SLinus Torvalds static int rpc_mount_count; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds 42e18b890bSChristoph Lameter static struct kmem_cache *rpc_inode_cachep __read_mostly; 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds #define RPC_UPCALL_TIMEOUT (30*HZ) 451da177e4SLinus Torvalds 462d00131aSStanislav Kinsbursky static BLOCKING_NOTIFIER_HEAD(rpc_pipefs_notifier_list); 472d00131aSStanislav Kinsbursky 482d00131aSStanislav Kinsbursky int rpc_pipefs_notifier_register(struct notifier_block *nb) 492d00131aSStanislav Kinsbursky { 502d00131aSStanislav Kinsbursky return blocking_notifier_chain_cond_register(&rpc_pipefs_notifier_list, nb); 512d00131aSStanislav Kinsbursky } 522d00131aSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_register); 532d00131aSStanislav Kinsbursky 542d00131aSStanislav Kinsbursky void rpc_pipefs_notifier_unregister(struct notifier_block *nb) 552d00131aSStanislav Kinsbursky { 562d00131aSStanislav Kinsbursky blocking_notifier_chain_unregister(&rpc_pipefs_notifier_list, nb); 572d00131aSStanislav Kinsbursky } 582d00131aSStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister); 592d00131aSStanislav Kinsbursky 609842ef35STrond Myklebust static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, 619842ef35STrond Myklebust void (*destroy_msg)(struct rpc_pipe_msg *), int err) 62b3eb67a2STrond Myklebust { 63b3eb67a2STrond Myklebust struct rpc_pipe_msg *msg; 64b3eb67a2STrond Myklebust 659842ef35STrond Myklebust if (list_empty(head)) 669842ef35STrond Myklebust return; 679842ef35STrond Myklebust do { 68b3eb67a2STrond Myklebust msg = list_entry(head->next, struct rpc_pipe_msg, list); 695a67657aSTrond Myklebust list_del_init(&msg->list); 70b3eb67a2STrond Myklebust msg->errno = err; 71b3eb67a2STrond Myklebust destroy_msg(msg); 729842ef35STrond Myklebust } while (!list_empty(head)); 731da177e4SLinus Torvalds wake_up(&rpci->waitq); 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds static void 7765f27f38SDavid Howells rpc_timeout_upcall_queue(struct work_struct *work) 781da177e4SLinus Torvalds { 799842ef35STrond Myklebust LIST_HEAD(free_list); 8065f27f38SDavid Howells struct rpc_inode *rpci = 8165f27f38SDavid Howells container_of(work, struct rpc_inode, queue_timeout.work); 821da177e4SLinus Torvalds struct inode *inode = &rpci->vfs_inode; 839842ef35STrond Myklebust void (*destroy_msg)(struct rpc_pipe_msg *); 841da177e4SLinus Torvalds 859842ef35STrond Myklebust spin_lock(&inode->i_lock); 869842ef35STrond Myklebust if (rpci->ops == NULL) { 879842ef35STrond Myklebust spin_unlock(&inode->i_lock); 889842ef35STrond Myklebust return; 899842ef35STrond Myklebust } 909842ef35STrond Myklebust destroy_msg = rpci->ops->destroy_msg; 919842ef35STrond Myklebust if (rpci->nreaders == 0) { 929842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 939842ef35STrond Myklebust rpci->pipelen = 0; 949842ef35STrond Myklebust } 959842ef35STrond Myklebust spin_unlock(&inode->i_lock); 969842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 99c1225158SPeng Tao ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg, 100c1225158SPeng Tao char __user *dst, size_t buflen) 101c1225158SPeng Tao { 102c1225158SPeng Tao char *data = (char *)msg->data + msg->copied; 103c1225158SPeng Tao size_t mlen = min(msg->len - msg->copied, buflen); 104c1225158SPeng Tao unsigned long left; 105c1225158SPeng Tao 106c1225158SPeng Tao left = copy_to_user(dst, data, mlen); 107c1225158SPeng Tao if (left == mlen) { 108c1225158SPeng Tao msg->errno = -EFAULT; 109c1225158SPeng Tao return -EFAULT; 110c1225158SPeng Tao } 111c1225158SPeng Tao 112c1225158SPeng Tao mlen -= left; 113c1225158SPeng Tao msg->copied += mlen; 114c1225158SPeng Tao msg->errno = 0; 115c1225158SPeng Tao return mlen; 116c1225158SPeng Tao } 117c1225158SPeng Tao EXPORT_SYMBOL_GPL(rpc_pipe_generic_upcall); 118c1225158SPeng Tao 11993a44a75SJ. Bruce Fields /** 1201a5778aaSBen Hutchings * rpc_queue_upcall - queue an upcall message to userspace 12193a44a75SJ. Bruce Fields * @inode: inode of upcall pipe on which to queue given message 12293a44a75SJ. Bruce Fields * @msg: message to queue 12393a44a75SJ. Bruce Fields * 12493a44a75SJ. Bruce Fields * Call with an @inode created by rpc_mkpipe() to queue an upcall. 12593a44a75SJ. Bruce Fields * A userspace process may then later read the upcall by performing a 12693a44a75SJ. Bruce Fields * read on an open file for this inode. It is up to the caller to 12793a44a75SJ. Bruce Fields * initialize the fields of @msg (other than @msg->list) appropriately. 12893a44a75SJ. Bruce Fields */ 1291da177e4SLinus Torvalds int 1301da177e4SLinus Torvalds rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) 1311da177e4SLinus Torvalds { 1321da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 1336070fe6fSTrond Myklebust int res = -EPIPE; 1341da177e4SLinus Torvalds 1359842ef35STrond Myklebust spin_lock(&inode->i_lock); 1366070fe6fSTrond Myklebust if (rpci->ops == NULL) 1376070fe6fSTrond Myklebust goto out; 1381da177e4SLinus Torvalds if (rpci->nreaders) { 1391da177e4SLinus Torvalds list_add_tail(&msg->list, &rpci->pipe); 1401da177e4SLinus Torvalds rpci->pipelen += msg->len; 1416070fe6fSTrond Myklebust res = 0; 1421da177e4SLinus Torvalds } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) { 1431da177e4SLinus Torvalds if (list_empty(&rpci->pipe)) 14424c5d9d7STrond Myklebust queue_delayed_work(rpciod_workqueue, 14524c5d9d7STrond Myklebust &rpci->queue_timeout, 1461da177e4SLinus Torvalds RPC_UPCALL_TIMEOUT); 1471da177e4SLinus Torvalds list_add_tail(&msg->list, &rpci->pipe); 1481da177e4SLinus Torvalds rpci->pipelen += msg->len; 1496070fe6fSTrond Myklebust res = 0; 1506070fe6fSTrond Myklebust } 1516070fe6fSTrond Myklebust out: 1529842ef35STrond Myklebust spin_unlock(&inode->i_lock); 1531da177e4SLinus Torvalds wake_up(&rpci->waitq); 1541da177e4SLinus Torvalds return res; 1551da177e4SLinus Torvalds } 156468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_queue_upcall); 1571da177e4SLinus Torvalds 1586070fe6fSTrond Myklebust static inline void 1596070fe6fSTrond Myklebust rpc_inode_setowner(struct inode *inode, void *private) 1606070fe6fSTrond Myklebust { 1616070fe6fSTrond Myklebust RPC_I(inode)->private = private; 1626070fe6fSTrond Myklebust } 1636070fe6fSTrond Myklebust 1641da177e4SLinus Torvalds static void 1651da177e4SLinus Torvalds rpc_close_pipes(struct inode *inode) 1661da177e4SLinus Torvalds { 1671da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 168b693ba4aSTrond Myklebust const struct rpc_pipe_ops *ops; 169e712804aS\"J. Bruce Fields\ int need_release; 1701da177e4SLinus Torvalds 1711b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 1729842ef35STrond Myklebust ops = rpci->ops; 1739842ef35STrond Myklebust if (ops != NULL) { 1749842ef35STrond Myklebust LIST_HEAD(free_list); 1759842ef35STrond Myklebust spin_lock(&inode->i_lock); 176e712804aS\"J. Bruce Fields\ need_release = rpci->nreaders != 0 || rpci->nwriters != 0; 1771da177e4SLinus Torvalds rpci->nreaders = 0; 1789842ef35STrond Myklebust list_splice_init(&rpci->in_upcall, &free_list); 1799842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 1809842ef35STrond Myklebust rpci->pipelen = 0; 1811da177e4SLinus Torvalds rpci->ops = NULL; 1829842ef35STrond Myklebust spin_unlock(&inode->i_lock); 1839842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); 1849842ef35STrond Myklebust rpci->nwriters = 0; 185e712804aS\"J. Bruce Fields\ if (need_release && ops->release_pipe) 1869842ef35STrond Myklebust ops->release_pipe(inode); 1874011cd97STrond Myklebust cancel_delayed_work_sync(&rpci->queue_timeout); 1881da177e4SLinus Torvalds } 1896070fe6fSTrond Myklebust rpc_inode_setowner(inode, NULL); 1901b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds static struct inode * 1941da177e4SLinus Torvalds rpc_alloc_inode(struct super_block *sb) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds struct rpc_inode *rpci; 197e94b1766SChristoph Lameter rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); 1981da177e4SLinus Torvalds if (!rpci) 1991da177e4SLinus Torvalds return NULL; 2001da177e4SLinus Torvalds return &rpci->vfs_inode; 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds static void 204fa0d7e3dSNick Piggin rpc_i_callback(struct rcu_head *head) 205fa0d7e3dSNick Piggin { 206fa0d7e3dSNick Piggin struct inode *inode = container_of(head, struct inode, i_rcu); 207fa0d7e3dSNick Piggin kmem_cache_free(rpc_inode_cachep, RPC_I(inode)); 208fa0d7e3dSNick Piggin } 209fa0d7e3dSNick Piggin 210fa0d7e3dSNick Piggin static void 2111da177e4SLinus Torvalds rpc_destroy_inode(struct inode *inode) 2121da177e4SLinus Torvalds { 213fa0d7e3dSNick Piggin call_rcu(&inode->i_rcu, rpc_i_callback); 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds static int 2171da177e4SLinus Torvalds rpc_pipe_open(struct inode *inode, struct file *filp) 2181da177e4SLinus Torvalds { 2191da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 220c3810608S\"J. Bruce Fields\ int first_open; 2211da177e4SLinus Torvalds int res = -ENXIO; 2221da177e4SLinus Torvalds 2231b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 224c3810608S\"J. Bruce Fields\ if (rpci->ops == NULL) 225c3810608S\"J. Bruce Fields\ goto out; 226c3810608S\"J. Bruce Fields\ first_open = rpci->nreaders == 0 && rpci->nwriters == 0; 227c3810608S\"J. Bruce Fields\ if (first_open && rpci->ops->open_pipe) { 228c3810608S\"J. Bruce Fields\ res = rpci->ops->open_pipe(inode); 229c3810608S\"J. Bruce Fields\ if (res) 230c3810608S\"J. Bruce Fields\ goto out; 231c3810608S\"J. Bruce Fields\ } 2321da177e4SLinus Torvalds if (filp->f_mode & FMODE_READ) 2331da177e4SLinus Torvalds rpci->nreaders++; 2341da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 2351da177e4SLinus Torvalds rpci->nwriters++; 2361da177e4SLinus Torvalds res = 0; 237c3810608S\"J. Bruce Fields\ out: 2381b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2391da177e4SLinus Torvalds return res; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds static int 2431da177e4SLinus Torvalds rpc_pipe_release(struct inode *inode, struct file *filp) 2441da177e4SLinus Torvalds { 245969b7f25STrond Myklebust struct rpc_inode *rpci = RPC_I(inode); 2461da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 247e712804aS\"J. Bruce Fields\ int last_close; 2481da177e4SLinus Torvalds 2491b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2501da177e4SLinus Torvalds if (rpci->ops == NULL) 2511da177e4SLinus Torvalds goto out; 252655b5bb4SJoe Perches msg = filp->private_data; 2531da177e4SLinus Torvalds if (msg != NULL) { 2549842ef35STrond Myklebust spin_lock(&inode->i_lock); 25548e49187STrond Myklebust msg->errno = -EAGAIN; 2565a67657aSTrond Myklebust list_del_init(&msg->list); 2579842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2581da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 2611da177e4SLinus Torvalds rpci->nwriters --; 2629842ef35STrond Myklebust if (filp->f_mode & FMODE_READ) { 2631da177e4SLinus Torvalds rpci->nreaders --; 2649842ef35STrond Myklebust if (rpci->nreaders == 0) { 2659842ef35STrond Myklebust LIST_HEAD(free_list); 2669842ef35STrond Myklebust spin_lock(&inode->i_lock); 2679842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 2689842ef35STrond Myklebust rpci->pipelen = 0; 2699842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2709842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, 2719842ef35STrond Myklebust rpci->ops->destroy_msg, -EAGAIN); 2729842ef35STrond Myklebust } 2739842ef35STrond Myklebust } 274e712804aS\"J. Bruce Fields\ last_close = rpci->nwriters == 0 && rpci->nreaders == 0; 275e712804aS\"J. Bruce Fields\ if (last_close && rpci->ops->release_pipe) 2761da177e4SLinus Torvalds rpci->ops->release_pipe(inode); 2771da177e4SLinus Torvalds out: 2781b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2791da177e4SLinus Torvalds return 0; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds static ssize_t 2831da177e4SLinus Torvalds rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) 2841da177e4SLinus Torvalds { 285303b46bbSJosef Sipek struct inode *inode = filp->f_path.dentry->d_inode; 2861da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 2871da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 2881da177e4SLinus Torvalds int res = 0; 2891da177e4SLinus Torvalds 2901b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2911da177e4SLinus Torvalds if (rpci->ops == NULL) { 2921da177e4SLinus Torvalds res = -EPIPE; 2931da177e4SLinus Torvalds goto out_unlock; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds msg = filp->private_data; 2961da177e4SLinus Torvalds if (msg == NULL) { 2979842ef35STrond Myklebust spin_lock(&inode->i_lock); 2981da177e4SLinus Torvalds if (!list_empty(&rpci->pipe)) { 2991da177e4SLinus Torvalds msg = list_entry(rpci->pipe.next, 3001da177e4SLinus Torvalds struct rpc_pipe_msg, 3011da177e4SLinus Torvalds list); 3021da177e4SLinus Torvalds list_move(&msg->list, &rpci->in_upcall); 3031da177e4SLinus Torvalds rpci->pipelen -= msg->len; 3041da177e4SLinus Torvalds filp->private_data = msg; 3051da177e4SLinus Torvalds msg->copied = 0; 3061da177e4SLinus Torvalds } 3079842ef35STrond Myklebust spin_unlock(&inode->i_lock); 3081da177e4SLinus Torvalds if (msg == NULL) 3091da177e4SLinus Torvalds goto out_unlock; 3101da177e4SLinus Torvalds } 3111da177e4SLinus Torvalds /* NOTE: it is up to the callback to update msg->copied */ 3121da177e4SLinus Torvalds res = rpci->ops->upcall(filp, msg, buf, len); 3131da177e4SLinus Torvalds if (res < 0 || msg->len == msg->copied) { 3141da177e4SLinus Torvalds filp->private_data = NULL; 3159842ef35STrond Myklebust spin_lock(&inode->i_lock); 3165a67657aSTrond Myklebust list_del_init(&msg->list); 3179842ef35STrond Myklebust spin_unlock(&inode->i_lock); 3181da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds out_unlock: 3211b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 3221da177e4SLinus Torvalds return res; 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds static ssize_t 3261da177e4SLinus Torvalds rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) 3271da177e4SLinus Torvalds { 328303b46bbSJosef Sipek struct inode *inode = filp->f_path.dentry->d_inode; 3291da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 3301da177e4SLinus Torvalds int res; 3311da177e4SLinus Torvalds 3321b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 3331da177e4SLinus Torvalds res = -EPIPE; 3341da177e4SLinus Torvalds if (rpci->ops != NULL) 3351da177e4SLinus Torvalds res = rpci->ops->downcall(filp, buf, len); 3361b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 3371da177e4SLinus Torvalds return res; 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds static unsigned int 3411da177e4SLinus Torvalds rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) 3421da177e4SLinus Torvalds { 3431da177e4SLinus Torvalds struct rpc_inode *rpci; 3441da177e4SLinus Torvalds unsigned int mask = 0; 3451da177e4SLinus Torvalds 346303b46bbSJosef Sipek rpci = RPC_I(filp->f_path.dentry->d_inode); 3471da177e4SLinus Torvalds poll_wait(filp, &rpci->waitq, wait); 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds mask = POLLOUT | POLLWRNORM; 3501da177e4SLinus Torvalds if (rpci->ops == NULL) 3511da177e4SLinus Torvalds mask |= POLLERR | POLLHUP; 352eda4f9b7SJ. Bruce Fields if (filp->private_data || !list_empty(&rpci->pipe)) 3531da177e4SLinus Torvalds mask |= POLLIN | POLLRDNORM; 3541da177e4SLinus Torvalds return mask; 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 357a6f8dbc6SArnd Bergmann static long 358a6f8dbc6SArnd Bergmann rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 3591da177e4SLinus Torvalds { 360a6f8dbc6SArnd Bergmann struct inode *inode = filp->f_path.dentry->d_inode; 361a6f8dbc6SArnd Bergmann struct rpc_inode *rpci = RPC_I(inode); 3621da177e4SLinus Torvalds int len; 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds switch (cmd) { 3651da177e4SLinus Torvalds case FIONREAD: 366a6f8dbc6SArnd Bergmann spin_lock(&inode->i_lock); 367a6f8dbc6SArnd Bergmann if (rpci->ops == NULL) { 368a6f8dbc6SArnd Bergmann spin_unlock(&inode->i_lock); 3691da177e4SLinus Torvalds return -EPIPE; 370a6f8dbc6SArnd Bergmann } 3711da177e4SLinus Torvalds len = rpci->pipelen; 3721da177e4SLinus Torvalds if (filp->private_data) { 3731da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 374655b5bb4SJoe Perches msg = filp->private_data; 3751da177e4SLinus Torvalds len += msg->len - msg->copied; 3761da177e4SLinus Torvalds } 377a6f8dbc6SArnd Bergmann spin_unlock(&inode->i_lock); 3781da177e4SLinus Torvalds return put_user(len, (int __user *)arg); 3791da177e4SLinus Torvalds default: 3801da177e4SLinus Torvalds return -EINVAL; 3811da177e4SLinus Torvalds } 3821da177e4SLinus Torvalds } 3831da177e4SLinus Torvalds 384da7071d7SArjan van de Ven static const struct file_operations rpc_pipe_fops = { 3851da177e4SLinus Torvalds .owner = THIS_MODULE, 3861da177e4SLinus Torvalds .llseek = no_llseek, 3871da177e4SLinus Torvalds .read = rpc_pipe_read, 3881da177e4SLinus Torvalds .write = rpc_pipe_write, 3891da177e4SLinus Torvalds .poll = rpc_pipe_poll, 390674b604cSFrederic Weisbecker .unlocked_ioctl = rpc_pipe_ioctl, 3911da177e4SLinus Torvalds .open = rpc_pipe_open, 3921da177e4SLinus Torvalds .release = rpc_pipe_release, 3931da177e4SLinus Torvalds }; 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds static int 3961da177e4SLinus Torvalds rpc_show_info(struct seq_file *m, void *v) 3971da177e4SLinus Torvalds { 3981da177e4SLinus Torvalds struct rpc_clnt *clnt = m->private; 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds seq_printf(m, "RPC server: %s\n", clnt->cl_server); 4011da177e4SLinus Torvalds seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, 4021da177e4SLinus Torvalds clnt->cl_prog, clnt->cl_vers); 403e7f78657SChuck Lever seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); 404e7f78657SChuck Lever seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); 405bf19aaceSJ. Bruce Fields seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); 4061da177e4SLinus Torvalds return 0; 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds static int 4101da177e4SLinus Torvalds rpc_info_open(struct inode *inode, struct file *file) 4111da177e4SLinus Torvalds { 412006abe88STrond Myklebust struct rpc_clnt *clnt = NULL; 4131da177e4SLinus Torvalds int ret = single_open(file, rpc_show_info, NULL); 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds if (!ret) { 4161da177e4SLinus Torvalds struct seq_file *m = file->private_data; 417006abe88STrond Myklebust 418006abe88STrond Myklebust spin_lock(&file->f_path.dentry->d_lock); 419006abe88STrond Myklebust if (!d_unhashed(file->f_path.dentry)) 4201da177e4SLinus Torvalds clnt = RPC_I(inode)->private; 421006abe88STrond Myklebust if (clnt != NULL && atomic_inc_not_zero(&clnt->cl_count)) { 422006abe88STrond Myklebust spin_unlock(&file->f_path.dentry->d_lock); 4231da177e4SLinus Torvalds m->private = clnt; 4241da177e4SLinus Torvalds } else { 425006abe88STrond Myklebust spin_unlock(&file->f_path.dentry->d_lock); 4261da177e4SLinus Torvalds single_release(inode, file); 4271da177e4SLinus Torvalds ret = -EINVAL; 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds } 4301da177e4SLinus Torvalds return ret; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds static int 4341da177e4SLinus Torvalds rpc_info_release(struct inode *inode, struct file *file) 4351da177e4SLinus Torvalds { 4361da177e4SLinus Torvalds struct seq_file *m = file->private_data; 4371da177e4SLinus Torvalds struct rpc_clnt *clnt = (struct rpc_clnt *)m->private; 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds if (clnt) 4401da177e4SLinus Torvalds rpc_release_client(clnt); 4411da177e4SLinus Torvalds return single_release(inode, file); 4421da177e4SLinus Torvalds } 4431da177e4SLinus Torvalds 444da7071d7SArjan van de Ven static const struct file_operations rpc_info_operations = { 4451da177e4SLinus Torvalds .owner = THIS_MODULE, 4461da177e4SLinus Torvalds .open = rpc_info_open, 4471da177e4SLinus Torvalds .read = seq_read, 4481da177e4SLinus Torvalds .llseek = seq_lseek, 4491da177e4SLinus Torvalds .release = rpc_info_release, 4501da177e4SLinus Torvalds }; 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds /* 4541da177e4SLinus Torvalds * Description of fs contents. 4551da177e4SLinus Torvalds */ 4561da177e4SLinus Torvalds struct rpc_filelist { 457ac6feceeSTrond Myklebust const char *name; 45899ac48f5SArjan van de Ven const struct file_operations *i_fop; 4597364af6aSTrond Myklebust umode_t mode; 4601da177e4SLinus Torvalds }; 4611da177e4SLinus Torvalds 46254281548STrond Myklebust struct vfsmount *rpc_get_mount(void) 4631da177e4SLinus Torvalds { 46454281548STrond Myklebust int err; 46554281548STrond Myklebust 466fc14f2feSAl Viro err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mnt, &rpc_mount_count); 46754281548STrond Myklebust if (err != 0) 46854281548STrond Myklebust return ERR_PTR(err); 469fc14f2feSAl Viro return rpc_mnt; 4701da177e4SLinus Torvalds } 471e571cbf1STrond Myklebust EXPORT_SYMBOL_GPL(rpc_get_mount); 4721da177e4SLinus Torvalds 47354281548STrond Myklebust void rpc_put_mount(void) 4741da177e4SLinus Torvalds { 475fc14f2feSAl Viro simple_release_fs(&rpc_mnt, &rpc_mount_count); 4761da177e4SLinus Torvalds } 477e571cbf1STrond Myklebust EXPORT_SYMBOL_GPL(rpc_put_mount); 4781da177e4SLinus Torvalds 479fe15ce44SNick Piggin static int rpc_delete_dentry(const struct dentry *dentry) 48062e1761cSTrond Myklebust { 48162e1761cSTrond Myklebust return 1; 48262e1761cSTrond Myklebust } 48362e1761cSTrond Myklebust 4843ba13d17SAl Viro static const struct dentry_operations rpc_dentry_operations = { 48562e1761cSTrond Myklebust .d_delete = rpc_delete_dentry, 48662e1761cSTrond Myklebust }; 48762e1761cSTrond Myklebust 4881da177e4SLinus Torvalds static struct inode * 4897364af6aSTrond Myklebust rpc_get_inode(struct super_block *sb, umode_t mode) 4901da177e4SLinus Torvalds { 4911da177e4SLinus Torvalds struct inode *inode = new_inode(sb); 4921da177e4SLinus Torvalds if (!inode) 4931da177e4SLinus Torvalds return NULL; 49485fe4025SChristoph Hellwig inode->i_ino = get_next_ino(); 4951da177e4SLinus Torvalds inode->i_mode = mode; 4961da177e4SLinus Torvalds inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 4971da177e4SLinus Torvalds switch (mode & S_IFMT) { 4981da177e4SLinus Torvalds case S_IFDIR: 4991da177e4SLinus Torvalds inode->i_fop = &simple_dir_operations; 5001da177e4SLinus Torvalds inode->i_op = &simple_dir_inode_operations; 501d8c76e6fSDave Hansen inc_nlink(inode); 5021da177e4SLinus Torvalds default: 5031da177e4SLinus Torvalds break; 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds return inode; 5061da177e4SLinus Torvalds } 5071da177e4SLinus Torvalds 5087589806eSTrond Myklebust static int __rpc_create_common(struct inode *dir, struct dentry *dentry, 5097589806eSTrond Myklebust umode_t mode, 5107589806eSTrond Myklebust const struct file_operations *i_fop, 5117589806eSTrond Myklebust void *private) 5127589806eSTrond Myklebust { 5137589806eSTrond Myklebust struct inode *inode; 5147589806eSTrond Myklebust 515beb0f0a9STrond Myklebust d_drop(dentry); 5167589806eSTrond Myklebust inode = rpc_get_inode(dir->i_sb, mode); 5177589806eSTrond Myklebust if (!inode) 5187589806eSTrond Myklebust goto out_err; 5197589806eSTrond Myklebust inode->i_ino = iunique(dir->i_sb, 100); 5207589806eSTrond Myklebust if (i_fop) 5217589806eSTrond Myklebust inode->i_fop = i_fop; 5227589806eSTrond Myklebust if (private) 5237589806eSTrond Myklebust rpc_inode_setowner(inode, private); 5247589806eSTrond Myklebust d_add(dentry, inode); 5257589806eSTrond Myklebust return 0; 5267589806eSTrond Myklebust out_err: 5277589806eSTrond Myklebust printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", 5287589806eSTrond Myklebust __FILE__, __func__, dentry->d_name.name); 5297589806eSTrond Myklebust dput(dentry); 5307589806eSTrond Myklebust return -ENOMEM; 5317589806eSTrond Myklebust } 5327589806eSTrond Myklebust 533ac6feceeSTrond Myklebust static int __rpc_create(struct inode *dir, struct dentry *dentry, 534ac6feceeSTrond Myklebust umode_t mode, 535ac6feceeSTrond Myklebust const struct file_operations *i_fop, 536ac6feceeSTrond Myklebust void *private) 537ac6feceeSTrond Myklebust { 538ac6feceeSTrond Myklebust int err; 539ac6feceeSTrond Myklebust 540ac6feceeSTrond Myklebust err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private); 541ac6feceeSTrond Myklebust if (err) 542ac6feceeSTrond Myklebust return err; 543ac6feceeSTrond Myklebust fsnotify_create(dir, dentry); 544ac6feceeSTrond Myklebust return 0; 545ac6feceeSTrond Myklebust } 546ac6feceeSTrond Myklebust 5477589806eSTrond Myklebust static int __rpc_mkdir(struct inode *dir, struct dentry *dentry, 5487589806eSTrond Myklebust umode_t mode, 5497589806eSTrond Myklebust const struct file_operations *i_fop, 5507589806eSTrond Myklebust void *private) 5517589806eSTrond Myklebust { 5527589806eSTrond Myklebust int err; 5537589806eSTrond Myklebust 5547589806eSTrond Myklebust err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private); 5557589806eSTrond Myklebust if (err) 5567589806eSTrond Myklebust return err; 5577589806eSTrond Myklebust inc_nlink(dir); 5587589806eSTrond Myklebust fsnotify_mkdir(dir, dentry); 5597589806eSTrond Myklebust return 0; 5607589806eSTrond Myklebust } 5617589806eSTrond Myklebust 5627589806eSTrond Myklebust static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, 5637589806eSTrond Myklebust umode_t mode, 5647589806eSTrond Myklebust const struct file_operations *i_fop, 5657589806eSTrond Myklebust void *private, 5667589806eSTrond Myklebust const struct rpc_pipe_ops *ops, 5677589806eSTrond Myklebust int flags) 5687589806eSTrond Myklebust { 5697589806eSTrond Myklebust struct rpc_inode *rpci; 5707589806eSTrond Myklebust int err; 5717589806eSTrond Myklebust 5727589806eSTrond Myklebust err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private); 5737589806eSTrond Myklebust if (err) 5747589806eSTrond Myklebust return err; 5757589806eSTrond Myklebust rpci = RPC_I(dentry->d_inode); 5767589806eSTrond Myklebust rpci->private = private; 5777589806eSTrond Myklebust rpci->flags = flags; 5787589806eSTrond Myklebust rpci->ops = ops; 5797589806eSTrond Myklebust fsnotify_create(dir, dentry); 5807589806eSTrond Myklebust return 0; 5817589806eSTrond Myklebust } 5827589806eSTrond Myklebust 583ac6feceeSTrond Myklebust static int __rpc_rmdir(struct inode *dir, struct dentry *dentry) 584ac6feceeSTrond Myklebust { 585ac6feceeSTrond Myklebust int ret; 586ac6feceeSTrond Myklebust 587ac6feceeSTrond Myklebust dget(dentry); 588ac6feceeSTrond Myklebust ret = simple_rmdir(dir, dentry); 589ac6feceeSTrond Myklebust d_delete(dentry); 590ac6feceeSTrond Myklebust dput(dentry); 591ac6feceeSTrond Myklebust return ret; 592ac6feceeSTrond Myklebust } 593ac6feceeSTrond Myklebust 594810d90bcSTrond Myklebust static int __rpc_unlink(struct inode *dir, struct dentry *dentry) 595810d90bcSTrond Myklebust { 596810d90bcSTrond Myklebust int ret; 597810d90bcSTrond Myklebust 598810d90bcSTrond Myklebust dget(dentry); 599810d90bcSTrond Myklebust ret = simple_unlink(dir, dentry); 600810d90bcSTrond Myklebust d_delete(dentry); 601810d90bcSTrond Myklebust dput(dentry); 602810d90bcSTrond Myklebust return ret; 603810d90bcSTrond Myklebust } 604810d90bcSTrond Myklebust 605810d90bcSTrond Myklebust static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry) 606810d90bcSTrond Myklebust { 607810d90bcSTrond Myklebust struct inode *inode = dentry->d_inode; 608810d90bcSTrond Myklebust 609810d90bcSTrond Myklebust rpc_close_pipes(inode); 610810d90bcSTrond Myklebust return __rpc_unlink(dir, dentry); 611810d90bcSTrond Myklebust } 612810d90bcSTrond Myklebust 613cfeaa4a3STrond Myklebust static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, 614cfeaa4a3STrond Myklebust struct qstr *name) 615cfeaa4a3STrond Myklebust { 616cfeaa4a3STrond Myklebust struct dentry *dentry; 617cfeaa4a3STrond Myklebust 6185bff0386SStanislav Kinsbursky dentry = d_lookup(parent, name); 6195bff0386SStanislav Kinsbursky if (!dentry) { 6205bff0386SStanislav Kinsbursky dentry = d_alloc(parent, name); 6215bff0386SStanislav Kinsbursky if (!dentry) 6225bff0386SStanislav Kinsbursky return ERR_PTR(-ENOMEM); 6235bff0386SStanislav Kinsbursky } 6245bff0386SStanislav Kinsbursky if (dentry->d_inode == NULL) { 6255bff0386SStanislav Kinsbursky d_set_d_op(dentry, &rpc_dentry_operations); 626f1f0abe1SDan Carpenter return dentry; 6275bff0386SStanislav Kinsbursky } 628cfeaa4a3STrond Myklebust dput(dentry); 629cfeaa4a3STrond Myklebust return ERR_PTR(-EEXIST); 630cfeaa4a3STrond Myklebust } 631cfeaa4a3STrond Myklebust 6321da177e4SLinus Torvalds /* 6331da177e4SLinus Torvalds * FIXME: This probably has races. 6341da177e4SLinus Torvalds */ 635ac6feceeSTrond Myklebust static void __rpc_depopulate(struct dentry *parent, 636ac6feceeSTrond Myklebust const struct rpc_filelist *files, 637ac6feceeSTrond Myklebust int start, int eof) 6381da177e4SLinus Torvalds { 6391da177e4SLinus Torvalds struct inode *dir = parent->d_inode; 640ac6feceeSTrond Myklebust struct dentry *dentry; 641ac6feceeSTrond Myklebust struct qstr name; 642ac6feceeSTrond Myklebust int i; 643ac6feceeSTrond Myklebust 644ac6feceeSTrond Myklebust for (i = start; i < eof; i++) { 645ac6feceeSTrond Myklebust name.name = files[i].name; 646ac6feceeSTrond Myklebust name.len = strlen(files[i].name); 647ac6feceeSTrond Myklebust name.hash = full_name_hash(name.name, name.len); 648ac6feceeSTrond Myklebust dentry = d_lookup(parent, &name); 649ac6feceeSTrond Myklebust 650ac6feceeSTrond Myklebust if (dentry == NULL) 651ac6feceeSTrond Myklebust continue; 652ac6feceeSTrond Myklebust if (dentry->d_inode == NULL) 653ac6feceeSTrond Myklebust goto next; 654ac6feceeSTrond Myklebust switch (dentry->d_inode->i_mode & S_IFMT) { 655ac6feceeSTrond Myklebust default: 656ac6feceeSTrond Myklebust BUG(); 657ac6feceeSTrond Myklebust case S_IFREG: 658ac6feceeSTrond Myklebust __rpc_unlink(dir, dentry); 659ac6feceeSTrond Myklebust break; 660ac6feceeSTrond Myklebust case S_IFDIR: 661ac6feceeSTrond Myklebust __rpc_rmdir(dir, dentry); 662ac6feceeSTrond Myklebust } 663ac6feceeSTrond Myklebust next: 664ac6feceeSTrond Myklebust dput(dentry); 665ac6feceeSTrond Myklebust } 666ac6feceeSTrond Myklebust } 667ac6feceeSTrond Myklebust 668ac6feceeSTrond Myklebust static void rpc_depopulate(struct dentry *parent, 669ac6feceeSTrond Myklebust const struct rpc_filelist *files, 670ac6feceeSTrond Myklebust int start, int eof) 671ac6feceeSTrond Myklebust { 672ac6feceeSTrond Myklebust struct inode *dir = parent->d_inode; 6731da177e4SLinus Torvalds 674c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD); 675ac6feceeSTrond Myklebust __rpc_depopulate(parent, files, start, eof); 6761b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 6771da177e4SLinus Torvalds } 6781da177e4SLinus Torvalds 679ac6feceeSTrond Myklebust static int rpc_populate(struct dentry *parent, 680ac6feceeSTrond Myklebust const struct rpc_filelist *files, 681ac6feceeSTrond Myklebust int start, int eof, 682ac6feceeSTrond Myklebust void *private) 6831da177e4SLinus Torvalds { 684ac6feceeSTrond Myklebust struct inode *dir = parent->d_inode; 6851da177e4SLinus Torvalds struct dentry *dentry; 686ac6feceeSTrond Myklebust int i, err; 6871da177e4SLinus Torvalds 6881b1dcc1bSJes Sorensen mutex_lock(&dir->i_mutex); 6891da177e4SLinus Torvalds for (i = start; i < eof; i++) { 690ac6feceeSTrond Myklebust struct qstr q; 691ac6feceeSTrond Myklebust 692ac6feceeSTrond Myklebust q.name = files[i].name; 693ac6feceeSTrond Myklebust q.len = strlen(files[i].name); 694ac6feceeSTrond Myklebust q.hash = full_name_hash(q.name, q.len); 695ac6feceeSTrond Myklebust dentry = __rpc_lookup_create_exclusive(parent, &q); 696ac6feceeSTrond Myklebust err = PTR_ERR(dentry); 697ac6feceeSTrond Myklebust if (IS_ERR(dentry)) 6981da177e4SLinus Torvalds goto out_bad; 699ac6feceeSTrond Myklebust switch (files[i].mode & S_IFMT) { 700ac6feceeSTrond Myklebust default: 701ac6feceeSTrond Myklebust BUG(); 702ac6feceeSTrond Myklebust case S_IFREG: 703ac6feceeSTrond Myklebust err = __rpc_create(dir, dentry, 704ac6feceeSTrond Myklebust files[i].mode, 705ac6feceeSTrond Myklebust files[i].i_fop, 706ac6feceeSTrond Myklebust private); 707ac6feceeSTrond Myklebust break; 708ac6feceeSTrond Myklebust case S_IFDIR: 709ac6feceeSTrond Myklebust err = __rpc_mkdir(dir, dentry, 710ac6feceeSTrond Myklebust files[i].mode, 711ac6feceeSTrond Myklebust NULL, 712ac6feceeSTrond Myklebust private); 7131da177e4SLinus Torvalds } 714ac6feceeSTrond Myklebust if (err != 0) 715ac6feceeSTrond Myklebust goto out_bad; 7161da177e4SLinus Torvalds } 7171b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 7181da177e4SLinus Torvalds return 0; 7191da177e4SLinus Torvalds out_bad: 720ac6feceeSTrond Myklebust __rpc_depopulate(parent, files, start, eof); 7211b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 7221da177e4SLinus Torvalds printk(KERN_WARNING "%s: %s failed to populate directory %s\n", 7230dc47877SHarvey Harrison __FILE__, __func__, parent->d_name.name); 724ac6feceeSTrond Myklebust return err; 725f134585aSTrond Myklebust } 726f134585aSTrond Myklebust 727e57aed77STrond Myklebust static struct dentry *rpc_mkdir_populate(struct dentry *parent, 728e57aed77STrond Myklebust struct qstr *name, umode_t mode, void *private, 729e57aed77STrond Myklebust int (*populate)(struct dentry *, void *), void *args_populate) 730f134585aSTrond Myklebust { 731f134585aSTrond Myklebust struct dentry *dentry; 7327d59d1e8STrond Myklebust struct inode *dir = parent->d_inode; 733f134585aSTrond Myklebust int error; 734f134585aSTrond Myklebust 7357d59d1e8STrond Myklebust mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 7367d59d1e8STrond Myklebust dentry = __rpc_lookup_create_exclusive(parent, name); 737f134585aSTrond Myklebust if (IS_ERR(dentry)) 7387d59d1e8STrond Myklebust goto out; 7397d59d1e8STrond Myklebust error = __rpc_mkdir(dir, dentry, mode, NULL, private); 7407589806eSTrond Myklebust if (error != 0) 7417589806eSTrond Myklebust goto out_err; 742e57aed77STrond Myklebust if (populate != NULL) { 743e57aed77STrond Myklebust error = populate(dentry, args_populate); 744f134585aSTrond Myklebust if (error) 745ac6feceeSTrond Myklebust goto err_rmdir; 746e57aed77STrond Myklebust } 747f134585aSTrond Myklebust out: 7481b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 7495c3e985aSTrond Myklebust return dentry; 750ac6feceeSTrond Myklebust err_rmdir: 751f134585aSTrond Myklebust __rpc_rmdir(dir, dentry); 7527589806eSTrond Myklebust out_err: 753f134585aSTrond Myklebust dentry = ERR_PTR(error); 754f134585aSTrond Myklebust goto out; 755f134585aSTrond Myklebust } 756f134585aSTrond Myklebust 757e57aed77STrond Myklebust static int rpc_rmdir_depopulate(struct dentry *dentry, 758e57aed77STrond Myklebust void (*depopulate)(struct dentry *)) 759f134585aSTrond Myklebust { 760dff02cc1STrond Myklebust struct dentry *parent; 761f134585aSTrond Myklebust struct inode *dir; 762f134585aSTrond Myklebust int error; 763f134585aSTrond Myklebust 764dff02cc1STrond Myklebust parent = dget_parent(dentry); 765dff02cc1STrond Myklebust dir = parent->d_inode; 766c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 767e57aed77STrond Myklebust if (depopulate != NULL) 768e57aed77STrond Myklebust depopulate(dentry); 769f134585aSTrond Myklebust error = __rpc_rmdir(dir, dentry); 7701b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 771dff02cc1STrond Myklebust dput(parent); 772f134585aSTrond Myklebust return error; 773f134585aSTrond Myklebust } 7741da177e4SLinus Torvalds 77593a44a75SJ. Bruce Fields /** 77693a44a75SJ. Bruce Fields * rpc_mkpipe - make an rpc_pipefs file for kernel<->userspace communication 77793a44a75SJ. Bruce Fields * @parent: dentry of directory to create new "pipe" in 77893a44a75SJ. Bruce Fields * @name: name of pipe 77993a44a75SJ. Bruce Fields * @private: private data to associate with the pipe, for the caller's use 78093a44a75SJ. Bruce Fields * @ops: operations defining the behavior of the pipe: upcall, downcall, 781c3810608S\"J. Bruce Fields\ * release_pipe, open_pipe, and destroy_msg. 78265b6e42cSRandy Dunlap * @flags: rpc_inode flags 78393a44a75SJ. Bruce Fields * 78493a44a75SJ. Bruce Fields * Data is made available for userspace to read by calls to 78593a44a75SJ. Bruce Fields * rpc_queue_upcall(). The actual reads will result in calls to 78693a44a75SJ. Bruce Fields * @ops->upcall, which will be called with the file pointer, 78793a44a75SJ. Bruce Fields * message, and userspace buffer to copy to. 78893a44a75SJ. Bruce Fields * 78993a44a75SJ. Bruce Fields * Writes can come at any time, and do not necessarily have to be 79093a44a75SJ. Bruce Fields * responses to upcalls. They will result in calls to @msg->downcall. 79193a44a75SJ. Bruce Fields * 79293a44a75SJ. Bruce Fields * The @private argument passed here will be available to all these methods 79393a44a75SJ. Bruce Fields * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. 79493a44a75SJ. Bruce Fields */ 795b693ba4aSTrond Myklebust struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, 796b693ba4aSTrond Myklebust void *private, const struct rpc_pipe_ops *ops, 797b693ba4aSTrond Myklebust int flags) 7981da177e4SLinus Torvalds { 7991da177e4SLinus Torvalds struct dentry *dentry; 8007589806eSTrond Myklebust struct inode *dir = parent->d_inode; 8017364af6aSTrond Myklebust umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR; 802cfeaa4a3STrond Myklebust struct qstr q; 8037589806eSTrond Myklebust int err; 8047364af6aSTrond Myklebust 8057364af6aSTrond Myklebust if (ops->upcall == NULL) 8067364af6aSTrond Myklebust umode &= ~S_IRUGO; 8077364af6aSTrond Myklebust if (ops->downcall == NULL) 8087364af6aSTrond Myklebust umode &= ~S_IWUGO; 8091da177e4SLinus Torvalds 810cfeaa4a3STrond Myklebust q.name = name; 811cfeaa4a3STrond Myklebust q.len = strlen(name); 812cfeaa4a3STrond Myklebust q.hash = full_name_hash(q.name, q.len), 813cfeaa4a3STrond Myklebust 814cfeaa4a3STrond Myklebust mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 8155bff0386SStanislav Kinsbursky dentry = __rpc_lookup_create_exclusive(parent, &q); 8161da177e4SLinus Torvalds if (IS_ERR(dentry)) 817cfeaa4a3STrond Myklebust goto out; 8187589806eSTrond Myklebust err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops, 8197589806eSTrond Myklebust private, ops, flags); 8207589806eSTrond Myklebust if (err) 8217589806eSTrond Myklebust goto out_err; 822f134585aSTrond Myklebust out: 8231b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 8245c3e985aSTrond Myklebust return dentry; 8257589806eSTrond Myklebust out_err: 8267589806eSTrond Myklebust dentry = ERR_PTR(err); 827158998b6STrond Myklebust printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", 8280dc47877SHarvey Harrison __FILE__, __func__, parent->d_name.name, name, 8297589806eSTrond Myklebust err); 830f134585aSTrond Myklebust goto out; 8311da177e4SLinus Torvalds } 832468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_mkpipe); 8331da177e4SLinus Torvalds 83493a44a75SJ. Bruce Fields /** 83593a44a75SJ. Bruce Fields * rpc_unlink - remove a pipe 83693a44a75SJ. Bruce Fields * @dentry: dentry for the pipe, as returned from rpc_mkpipe 83793a44a75SJ. Bruce Fields * 83893a44a75SJ. Bruce Fields * After this call, lookups will no longer find the pipe, and any 83993a44a75SJ. Bruce Fields * attempts to read or write using preexisting opens of the pipe will 84093a44a75SJ. Bruce Fields * return -EPIPE. 84193a44a75SJ. Bruce Fields */ 842f134585aSTrond Myklebust int 8435d67476fSTrond Myklebust rpc_unlink(struct dentry *dentry) 8441da177e4SLinus Torvalds { 8455d67476fSTrond Myklebust struct dentry *parent; 846f134585aSTrond Myklebust struct inode *dir; 8475d67476fSTrond Myklebust int error = 0; 8481da177e4SLinus Torvalds 8495d67476fSTrond Myklebust parent = dget_parent(dentry); 8505d67476fSTrond Myklebust dir = parent->d_inode; 851c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 852810d90bcSTrond Myklebust error = __rpc_rmpipe(dir, dentry); 8531b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 8545d67476fSTrond Myklebust dput(parent); 855f134585aSTrond Myklebust return error; 8561da177e4SLinus Torvalds } 857468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_unlink); 8581da177e4SLinus Torvalds 859e57aed77STrond Myklebust enum { 860e57aed77STrond Myklebust RPCAUTH_info, 861e57aed77STrond Myklebust RPCAUTH_EOF 862e57aed77STrond Myklebust }; 863e57aed77STrond Myklebust 864e57aed77STrond Myklebust static const struct rpc_filelist authfiles[] = { 865e57aed77STrond Myklebust [RPCAUTH_info] = { 866e57aed77STrond Myklebust .name = "info", 867e57aed77STrond Myklebust .i_fop = &rpc_info_operations, 868e57aed77STrond Myklebust .mode = S_IFREG | S_IRUSR, 869e57aed77STrond Myklebust }, 870e57aed77STrond Myklebust }; 871e57aed77STrond Myklebust 872e57aed77STrond Myklebust static int rpc_clntdir_populate(struct dentry *dentry, void *private) 873e57aed77STrond Myklebust { 874e57aed77STrond Myklebust return rpc_populate(dentry, 875e57aed77STrond Myklebust authfiles, RPCAUTH_info, RPCAUTH_EOF, 876e57aed77STrond Myklebust private); 877e57aed77STrond Myklebust } 878e57aed77STrond Myklebust 879e57aed77STrond Myklebust static void rpc_clntdir_depopulate(struct dentry *dentry) 880e57aed77STrond Myklebust { 881e57aed77STrond Myklebust rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF); 882e57aed77STrond Myklebust } 883e57aed77STrond Myklebust 8847d59d1e8STrond Myklebust /** 8857d59d1e8STrond Myklebust * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs 8864111d4fdSRandy Dunlap * @dentry: dentry from the rpc_pipefs root to the new directory 8874111d4fdSRandy Dunlap * @name: &struct qstr for the name 8887d59d1e8STrond Myklebust * @rpc_client: rpc client to associate with this directory 8897d59d1e8STrond Myklebust * 8907d59d1e8STrond Myklebust * This creates a directory at the given @path associated with 8917d59d1e8STrond Myklebust * @rpc_clnt, which will contain a file named "info" with some basic 8927d59d1e8STrond Myklebust * information about the client, together with any "pipes" that may 8937d59d1e8STrond Myklebust * later be created using rpc_mkpipe(). 8947d59d1e8STrond Myklebust */ 89523ac6581STrond Myklebust struct dentry *rpc_create_client_dir(struct dentry *dentry, 89623ac6581STrond Myklebust struct qstr *name, 8977d59d1e8STrond Myklebust struct rpc_clnt *rpc_client) 8987d59d1e8STrond Myklebust { 899e57aed77STrond Myklebust return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL, 900e57aed77STrond Myklebust rpc_clntdir_populate, rpc_client); 901e57aed77STrond Myklebust } 902e57aed77STrond Myklebust 903e57aed77STrond Myklebust /** 904e57aed77STrond Myklebust * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() 905e57aed77STrond Myklebust * @dentry: directory to remove 906e57aed77STrond Myklebust */ 907e57aed77STrond Myklebust int rpc_remove_client_dir(struct dentry *dentry) 908e57aed77STrond Myklebust { 909e57aed77STrond Myklebust return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate); 9107d59d1e8STrond Myklebust } 9117d59d1e8STrond Myklebust 9128854e82dSTrond Myklebust static const struct rpc_filelist cache_pipefs_files[3] = { 9138854e82dSTrond Myklebust [0] = { 9148854e82dSTrond Myklebust .name = "channel", 9158854e82dSTrond Myklebust .i_fop = &cache_file_operations_pipefs, 91696c61cbdSTrond Myklebust .mode = S_IFREG|S_IRUSR|S_IWUSR, 9178854e82dSTrond Myklebust }, 9188854e82dSTrond Myklebust [1] = { 9198854e82dSTrond Myklebust .name = "content", 9208854e82dSTrond Myklebust .i_fop = &content_file_operations_pipefs, 9218854e82dSTrond Myklebust .mode = S_IFREG|S_IRUSR, 9228854e82dSTrond Myklebust }, 9238854e82dSTrond Myklebust [2] = { 9248854e82dSTrond Myklebust .name = "flush", 9258854e82dSTrond Myklebust .i_fop = &cache_flush_operations_pipefs, 9268854e82dSTrond Myklebust .mode = S_IFREG|S_IRUSR|S_IWUSR, 9278854e82dSTrond Myklebust }, 9288854e82dSTrond Myklebust }; 9298854e82dSTrond Myklebust 9308854e82dSTrond Myklebust static int rpc_cachedir_populate(struct dentry *dentry, void *private) 9318854e82dSTrond Myklebust { 9328854e82dSTrond Myklebust return rpc_populate(dentry, 9338854e82dSTrond Myklebust cache_pipefs_files, 0, 3, 9348854e82dSTrond Myklebust private); 9358854e82dSTrond Myklebust } 9368854e82dSTrond Myklebust 9378854e82dSTrond Myklebust static void rpc_cachedir_depopulate(struct dentry *dentry) 9388854e82dSTrond Myklebust { 9398854e82dSTrond Myklebust rpc_depopulate(dentry, cache_pipefs_files, 0, 3); 9408854e82dSTrond Myklebust } 9418854e82dSTrond Myklebust 9428854e82dSTrond Myklebust struct dentry *rpc_create_cache_dir(struct dentry *parent, struct qstr *name, 94364f1426fSAl Viro umode_t umode, struct cache_detail *cd) 9448854e82dSTrond Myklebust { 9458854e82dSTrond Myklebust return rpc_mkdir_populate(parent, name, umode, NULL, 9468854e82dSTrond Myklebust rpc_cachedir_populate, cd); 9478854e82dSTrond Myklebust } 9488854e82dSTrond Myklebust 9498854e82dSTrond Myklebust void rpc_remove_cache_dir(struct dentry *dentry) 9508854e82dSTrond Myklebust { 9518854e82dSTrond Myklebust rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate); 9528854e82dSTrond Myklebust } 9538854e82dSTrond Myklebust 9541da177e4SLinus Torvalds /* 9551da177e4SLinus Torvalds * populate the filesystem 9561da177e4SLinus Torvalds */ 957b87221deSAlexey Dobriyan static const struct super_operations s_ops = { 9581da177e4SLinus Torvalds .alloc_inode = rpc_alloc_inode, 9591da177e4SLinus Torvalds .destroy_inode = rpc_destroy_inode, 9601da177e4SLinus Torvalds .statfs = simple_statfs, 9611da177e4SLinus Torvalds }; 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds #define RPCAUTH_GSSMAGIC 0x67596969 9641da177e4SLinus Torvalds 965bb156749STrond Myklebust /* 966bb156749STrond Myklebust * We have a single directory with 1 node in it. 967bb156749STrond Myklebust */ 968bb156749STrond Myklebust enum { 969bb156749STrond Myklebust RPCAUTH_lockd, 970bb156749STrond Myklebust RPCAUTH_mount, 971bb156749STrond Myklebust RPCAUTH_nfs, 972bb156749STrond Myklebust RPCAUTH_portmap, 973bb156749STrond Myklebust RPCAUTH_statd, 974bb156749STrond Myklebust RPCAUTH_nfsd4_cb, 975e571cbf1STrond Myklebust RPCAUTH_cache, 976bb156749STrond Myklebust RPCAUTH_RootEOF 977bb156749STrond Myklebust }; 978bb156749STrond Myklebust 979bb156749STrond Myklebust static const struct rpc_filelist files[] = { 980bb156749STrond Myklebust [RPCAUTH_lockd] = { 981bb156749STrond Myklebust .name = "lockd", 982bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 983bb156749STrond Myklebust }, 984bb156749STrond Myklebust [RPCAUTH_mount] = { 985bb156749STrond Myklebust .name = "mount", 986bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 987bb156749STrond Myklebust }, 988bb156749STrond Myklebust [RPCAUTH_nfs] = { 989bb156749STrond Myklebust .name = "nfs", 990bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 991bb156749STrond Myklebust }, 992bb156749STrond Myklebust [RPCAUTH_portmap] = { 993bb156749STrond Myklebust .name = "portmap", 994bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 995bb156749STrond Myklebust }, 996bb156749STrond Myklebust [RPCAUTH_statd] = { 997bb156749STrond Myklebust .name = "statd", 998bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 999bb156749STrond Myklebust }, 1000bb156749STrond Myklebust [RPCAUTH_nfsd4_cb] = { 1001bb156749STrond Myklebust .name = "nfsd4_cb", 1002bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 1003bb156749STrond Myklebust }, 1004e571cbf1STrond Myklebust [RPCAUTH_cache] = { 1005e571cbf1STrond Myklebust .name = "cache", 1006e571cbf1STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 1007e571cbf1STrond Myklebust }, 1008bb156749STrond Myklebust }; 1009bb156749STrond Myklebust 1010432eb1a5SStanislav Kinsbursky /* 1011432eb1a5SStanislav Kinsbursky * This call can be used only in RPC pipefs mount notification hooks. 1012432eb1a5SStanislav Kinsbursky */ 1013432eb1a5SStanislav Kinsbursky struct dentry *rpc_d_lookup_sb(const struct super_block *sb, 1014432eb1a5SStanislav Kinsbursky const unsigned char *dir_name) 1015432eb1a5SStanislav Kinsbursky { 1016432eb1a5SStanislav Kinsbursky struct qstr dir = { 1017432eb1a5SStanislav Kinsbursky .name = dir_name, 1018432eb1a5SStanislav Kinsbursky .len = strlen(dir_name), 1019432eb1a5SStanislav Kinsbursky .hash = full_name_hash(dir_name, strlen(dir_name)), 1020432eb1a5SStanislav Kinsbursky }; 1021432eb1a5SStanislav Kinsbursky 1022432eb1a5SStanislav Kinsbursky return d_lookup(sb->s_root, &dir); 1023432eb1a5SStanislav Kinsbursky } 1024432eb1a5SStanislav Kinsbursky EXPORT_SYMBOL_GPL(rpc_d_lookup_sb); 1025432eb1a5SStanislav Kinsbursky 10261da177e4SLinus Torvalds static int 10271da177e4SLinus Torvalds rpc_fill_super(struct super_block *sb, void *data, int silent) 10281da177e4SLinus Torvalds { 10291da177e4SLinus Torvalds struct inode *inode; 10301da177e4SLinus Torvalds struct dentry *root; 103138b0da75SStanislav Kinsbursky struct net *net = data; 10322d00131aSStanislav Kinsbursky int err; 10331da177e4SLinus Torvalds 10341da177e4SLinus Torvalds sb->s_blocksize = PAGE_CACHE_SIZE; 10351da177e4SLinus Torvalds sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 10361da177e4SLinus Torvalds sb->s_magic = RPCAUTH_GSSMAGIC; 10371da177e4SLinus Torvalds sb->s_op = &s_ops; 10381da177e4SLinus Torvalds sb->s_time_gran = 1; 10391da177e4SLinus Torvalds 10401da177e4SLinus Torvalds inode = rpc_get_inode(sb, S_IFDIR | 0755); 10411da177e4SLinus Torvalds if (!inode) 10421da177e4SLinus Torvalds return -ENOMEM; 1043fc7bed8cSAl Viro sb->s_root = root = d_alloc_root(inode); 10441da177e4SLinus Torvalds if (!root) { 10451da177e4SLinus Torvalds iput(inode); 10461da177e4SLinus Torvalds return -ENOMEM; 10471da177e4SLinus Torvalds } 1048ac6feceeSTrond Myklebust if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) 10491da177e4SLinus Torvalds return -ENOMEM; 10502d00131aSStanislav Kinsbursky err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list, 10512d00131aSStanislav Kinsbursky RPC_PIPEFS_MOUNT, 10522d00131aSStanislav Kinsbursky sb); 10532d00131aSStanislav Kinsbursky if (err) 10542d00131aSStanislav Kinsbursky goto err_depopulate; 1055021c68deSStanislav Kinsbursky sb->s_fs_info = get_net(net); 1056fc7bed8cSAl Viro return 0; 10572d00131aSStanislav Kinsbursky 10582d00131aSStanislav Kinsbursky err_depopulate: 10592d00131aSStanislav Kinsbursky blocking_notifier_call_chain(&rpc_pipefs_notifier_list, 10602d00131aSStanislav Kinsbursky RPC_PIPEFS_UMOUNT, 10612d00131aSStanislav Kinsbursky sb); 10622d00131aSStanislav Kinsbursky __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF); 10632d00131aSStanislav Kinsbursky return err; 10641da177e4SLinus Torvalds } 10651da177e4SLinus Torvalds 1066fc14f2feSAl Viro static struct dentry * 1067fc14f2feSAl Viro rpc_mount(struct file_system_type *fs_type, 1068fc14f2feSAl Viro int flags, const char *dev_name, void *data) 10691da177e4SLinus Torvalds { 107038b0da75SStanislav Kinsbursky return mount_ns(fs_type, flags, current->nsproxy->net_ns, rpc_fill_super); 10711da177e4SLinus Torvalds } 10721da177e4SLinus Torvalds 1073021c68deSStanislav Kinsbursky void rpc_kill_sb(struct super_block *sb) 1074021c68deSStanislav Kinsbursky { 1075021c68deSStanislav Kinsbursky struct net *net = sb->s_fs_info; 1076021c68deSStanislav Kinsbursky 1077021c68deSStanislav Kinsbursky put_net(net); 10782d00131aSStanislav Kinsbursky blocking_notifier_call_chain(&rpc_pipefs_notifier_list, 10792d00131aSStanislav Kinsbursky RPC_PIPEFS_UMOUNT, 10802d00131aSStanislav Kinsbursky sb); 1081021c68deSStanislav Kinsbursky kill_litter_super(sb); 1082021c68deSStanislav Kinsbursky } 1083021c68deSStanislav Kinsbursky 10841da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type = { 10851da177e4SLinus Torvalds .owner = THIS_MODULE, 10861da177e4SLinus Torvalds .name = "rpc_pipefs", 1087fc14f2feSAl Viro .mount = rpc_mount, 1088021c68deSStanislav Kinsbursky .kill_sb = rpc_kill_sb, 10891da177e4SLinus Torvalds }; 10901da177e4SLinus Torvalds 10911da177e4SLinus Torvalds static void 109251cc5068SAlexey Dobriyan init_once(void *foo) 10931da177e4SLinus Torvalds { 10941da177e4SLinus Torvalds struct rpc_inode *rpci = (struct rpc_inode *) foo; 10951da177e4SLinus Torvalds 10961da177e4SLinus Torvalds inode_init_once(&rpci->vfs_inode); 10971da177e4SLinus Torvalds rpci->private = NULL; 10981da177e4SLinus Torvalds rpci->nreaders = 0; 10991da177e4SLinus Torvalds rpci->nwriters = 0; 11001da177e4SLinus Torvalds INIT_LIST_HEAD(&rpci->in_upcall); 11016e84c7b6STrond Myklebust INIT_LIST_HEAD(&rpci->in_downcall); 11021da177e4SLinus Torvalds INIT_LIST_HEAD(&rpci->pipe); 11031da177e4SLinus Torvalds rpci->pipelen = 0; 11041da177e4SLinus Torvalds init_waitqueue_head(&rpci->waitq); 110552bad64dSDavid Howells INIT_DELAYED_WORK(&rpci->queue_timeout, 110665f27f38SDavid Howells rpc_timeout_upcall_queue); 11071da177e4SLinus Torvalds rpci->ops = NULL; 11081da177e4SLinus Torvalds } 11091da177e4SLinus Torvalds 11101da177e4SLinus Torvalds int register_rpc_pipefs(void) 11111da177e4SLinus Torvalds { 11125bd5f581SAkinobu Mita int err; 11135bd5f581SAkinobu Mita 11141da177e4SLinus Torvalds rpc_inode_cachep = kmem_cache_create("rpc_inode_cache", 11151da177e4SLinus Torvalds sizeof(struct rpc_inode), 1116fffb60f9SPaul Jackson 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| 1117fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 111820c2df83SPaul Mundt init_once); 11191da177e4SLinus Torvalds if (!rpc_inode_cachep) 11201da177e4SLinus Torvalds return -ENOMEM; 11215bd5f581SAkinobu Mita err = register_filesystem(&rpc_pipe_fs_type); 11225bd5f581SAkinobu Mita if (err) { 11235bd5f581SAkinobu Mita kmem_cache_destroy(rpc_inode_cachep); 11245bd5f581SAkinobu Mita return err; 11255bd5f581SAkinobu Mita } 11265bd5f581SAkinobu Mita 11271da177e4SLinus Torvalds return 0; 11281da177e4SLinus Torvalds } 11291da177e4SLinus Torvalds 11301da177e4SLinus Torvalds void unregister_rpc_pipefs(void) 11311da177e4SLinus Torvalds { 11321a1d92c1SAlexey Dobriyan kmem_cache_destroy(rpc_inode_cachep); 11331da177e4SLinus Torvalds unregister_filesystem(&rpc_pipe_fs_type); 11341da177e4SLinus Torvalds } 1135dcbf8c30SMichal Schmidt 1136dcbf8c30SMichal Schmidt /* Make 'mount -t rpc_pipefs ...' autoload this module. */ 1137dcbf8c30SMichal Schmidt MODULE_ALIAS("rpc_pipefs"); 1138