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> 301da177e4SLinus Torvalds 31ba89966cSEric Dumazet static struct vfsmount *rpc_mount __read_mostly; 321da177e4SLinus Torvalds static int rpc_mount_count; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type; 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds 37e18b890bSChristoph Lameter static struct kmem_cache *rpc_inode_cachep __read_mostly; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds #define RPC_UPCALL_TIMEOUT (30*HZ) 401da177e4SLinus Torvalds 419842ef35STrond Myklebust static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, 429842ef35STrond Myklebust void (*destroy_msg)(struct rpc_pipe_msg *), int err) 43b3eb67a2STrond Myklebust { 44b3eb67a2STrond Myklebust struct rpc_pipe_msg *msg; 45b3eb67a2STrond Myklebust 469842ef35STrond Myklebust if (list_empty(head)) 479842ef35STrond Myklebust return; 489842ef35STrond Myklebust do { 49b3eb67a2STrond Myklebust msg = list_entry(head->next, struct rpc_pipe_msg, list); 509842ef35STrond Myklebust list_del(&msg->list); 51b3eb67a2STrond Myklebust msg->errno = err; 52b3eb67a2STrond Myklebust destroy_msg(msg); 539842ef35STrond Myklebust } while (!list_empty(head)); 541da177e4SLinus Torvalds wake_up(&rpci->waitq); 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds static void 5865f27f38SDavid Howells rpc_timeout_upcall_queue(struct work_struct *work) 591da177e4SLinus Torvalds { 609842ef35STrond Myklebust LIST_HEAD(free_list); 6165f27f38SDavid Howells struct rpc_inode *rpci = 6265f27f38SDavid Howells container_of(work, struct rpc_inode, queue_timeout.work); 631da177e4SLinus Torvalds struct inode *inode = &rpci->vfs_inode; 649842ef35STrond Myklebust void (*destroy_msg)(struct rpc_pipe_msg *); 651da177e4SLinus Torvalds 669842ef35STrond Myklebust spin_lock(&inode->i_lock); 679842ef35STrond Myklebust if (rpci->ops == NULL) { 689842ef35STrond Myklebust spin_unlock(&inode->i_lock); 699842ef35STrond Myklebust return; 709842ef35STrond Myklebust } 719842ef35STrond Myklebust destroy_msg = rpci->ops->destroy_msg; 729842ef35STrond Myklebust if (rpci->nreaders == 0) { 739842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 749842ef35STrond Myklebust rpci->pipelen = 0; 759842ef35STrond Myklebust } 769842ef35STrond Myklebust spin_unlock(&inode->i_lock); 779842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 8093a44a75SJ. Bruce Fields /** 811a5778aaSBen Hutchings * rpc_queue_upcall - queue an upcall message to userspace 8293a44a75SJ. Bruce Fields * @inode: inode of upcall pipe on which to queue given message 8393a44a75SJ. Bruce Fields * @msg: message to queue 8493a44a75SJ. Bruce Fields * 8593a44a75SJ. Bruce Fields * Call with an @inode created by rpc_mkpipe() to queue an upcall. 8693a44a75SJ. Bruce Fields * A userspace process may then later read the upcall by performing a 8793a44a75SJ. Bruce Fields * read on an open file for this inode. It is up to the caller to 8893a44a75SJ. Bruce Fields * initialize the fields of @msg (other than @msg->list) appropriately. 8993a44a75SJ. Bruce Fields */ 901da177e4SLinus Torvalds int 911da177e4SLinus Torvalds rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) 921da177e4SLinus Torvalds { 931da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 946070fe6fSTrond Myklebust int res = -EPIPE; 951da177e4SLinus Torvalds 969842ef35STrond Myklebust spin_lock(&inode->i_lock); 976070fe6fSTrond Myklebust if (rpci->ops == NULL) 986070fe6fSTrond Myklebust goto out; 991da177e4SLinus Torvalds if (rpci->nreaders) { 1001da177e4SLinus Torvalds list_add_tail(&msg->list, &rpci->pipe); 1011da177e4SLinus Torvalds rpci->pipelen += msg->len; 1026070fe6fSTrond Myklebust res = 0; 1031da177e4SLinus Torvalds } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) { 1041da177e4SLinus Torvalds if (list_empty(&rpci->pipe)) 10524c5d9d7STrond Myklebust queue_delayed_work(rpciod_workqueue, 10624c5d9d7STrond Myklebust &rpci->queue_timeout, 1071da177e4SLinus Torvalds RPC_UPCALL_TIMEOUT); 1081da177e4SLinus Torvalds list_add_tail(&msg->list, &rpci->pipe); 1091da177e4SLinus Torvalds rpci->pipelen += msg->len; 1106070fe6fSTrond Myklebust res = 0; 1116070fe6fSTrond Myklebust } 1126070fe6fSTrond Myklebust out: 1139842ef35STrond Myklebust spin_unlock(&inode->i_lock); 1141da177e4SLinus Torvalds wake_up(&rpci->waitq); 1151da177e4SLinus Torvalds return res; 1161da177e4SLinus Torvalds } 117468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_queue_upcall); 1181da177e4SLinus Torvalds 1196070fe6fSTrond Myklebust static inline void 1206070fe6fSTrond Myklebust rpc_inode_setowner(struct inode *inode, void *private) 1216070fe6fSTrond Myklebust { 1226070fe6fSTrond Myklebust RPC_I(inode)->private = private; 1236070fe6fSTrond Myklebust } 1246070fe6fSTrond Myklebust 1251da177e4SLinus Torvalds static void 1261da177e4SLinus Torvalds rpc_close_pipes(struct inode *inode) 1271da177e4SLinus Torvalds { 1281da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 129b693ba4aSTrond Myklebust const struct rpc_pipe_ops *ops; 130e712804aS\"J. Bruce Fields\ int need_release; 1311da177e4SLinus Torvalds 1321b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 1339842ef35STrond Myklebust ops = rpci->ops; 1349842ef35STrond Myklebust if (ops != NULL) { 1359842ef35STrond Myklebust LIST_HEAD(free_list); 1369842ef35STrond Myklebust spin_lock(&inode->i_lock); 137e712804aS\"J. Bruce Fields\ need_release = rpci->nreaders != 0 || rpci->nwriters != 0; 1381da177e4SLinus Torvalds rpci->nreaders = 0; 1399842ef35STrond Myklebust list_splice_init(&rpci->in_upcall, &free_list); 1409842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 1419842ef35STrond Myklebust rpci->pipelen = 0; 1421da177e4SLinus Torvalds rpci->ops = NULL; 1439842ef35STrond Myklebust spin_unlock(&inode->i_lock); 1449842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); 1459842ef35STrond Myklebust rpci->nwriters = 0; 146e712804aS\"J. Bruce Fields\ if (need_release && ops->release_pipe) 1479842ef35STrond Myklebust ops->release_pipe(inode); 1484011cd97STrond Myklebust cancel_delayed_work_sync(&rpci->queue_timeout); 1491da177e4SLinus Torvalds } 1506070fe6fSTrond Myklebust rpc_inode_setowner(inode, NULL); 1511b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds static struct inode * 1551da177e4SLinus Torvalds rpc_alloc_inode(struct super_block *sb) 1561da177e4SLinus Torvalds { 1571da177e4SLinus Torvalds struct rpc_inode *rpci; 158e94b1766SChristoph Lameter rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); 1591da177e4SLinus Torvalds if (!rpci) 1601da177e4SLinus Torvalds return NULL; 1611da177e4SLinus Torvalds return &rpci->vfs_inode; 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds static void 1651da177e4SLinus Torvalds rpc_destroy_inode(struct inode *inode) 1661da177e4SLinus Torvalds { 1671da177e4SLinus Torvalds kmem_cache_free(rpc_inode_cachep, RPC_I(inode)); 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds static int 1711da177e4SLinus Torvalds rpc_pipe_open(struct inode *inode, struct file *filp) 1721da177e4SLinus Torvalds { 1731da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 174c3810608S\"J. Bruce Fields\ int first_open; 1751da177e4SLinus Torvalds int res = -ENXIO; 1761da177e4SLinus Torvalds 1771b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 178c3810608S\"J. Bruce Fields\ if (rpci->ops == NULL) 179c3810608S\"J. Bruce Fields\ goto out; 180c3810608S\"J. Bruce Fields\ first_open = rpci->nreaders == 0 && rpci->nwriters == 0; 181c3810608S\"J. Bruce Fields\ if (first_open && rpci->ops->open_pipe) { 182c3810608S\"J. Bruce Fields\ res = rpci->ops->open_pipe(inode); 183c3810608S\"J. Bruce Fields\ if (res) 184c3810608S\"J. Bruce Fields\ goto out; 185c3810608S\"J. Bruce Fields\ } 1861da177e4SLinus Torvalds if (filp->f_mode & FMODE_READ) 1871da177e4SLinus Torvalds rpci->nreaders++; 1881da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 1891da177e4SLinus Torvalds rpci->nwriters++; 1901da177e4SLinus Torvalds res = 0; 191c3810608S\"J. Bruce Fields\ out: 1921b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 1931da177e4SLinus Torvalds return res; 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds static int 1971da177e4SLinus Torvalds rpc_pipe_release(struct inode *inode, struct file *filp) 1981da177e4SLinus Torvalds { 199969b7f25STrond Myklebust struct rpc_inode *rpci = RPC_I(inode); 2001da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 201e712804aS\"J. Bruce Fields\ int last_close; 2021da177e4SLinus Torvalds 2031b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2041da177e4SLinus Torvalds if (rpci->ops == NULL) 2051da177e4SLinus Torvalds goto out; 2061da177e4SLinus Torvalds msg = (struct rpc_pipe_msg *)filp->private_data; 2071da177e4SLinus Torvalds if (msg != NULL) { 2089842ef35STrond Myklebust spin_lock(&inode->i_lock); 20948e49187STrond Myklebust msg->errno = -EAGAIN; 2109842ef35STrond Myklebust list_del(&msg->list); 2119842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2121da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 2151da177e4SLinus Torvalds rpci->nwriters --; 2169842ef35STrond Myklebust if (filp->f_mode & FMODE_READ) { 2171da177e4SLinus Torvalds rpci->nreaders --; 2189842ef35STrond Myklebust if (rpci->nreaders == 0) { 2199842ef35STrond Myklebust LIST_HEAD(free_list); 2209842ef35STrond Myklebust spin_lock(&inode->i_lock); 2219842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 2229842ef35STrond Myklebust rpci->pipelen = 0; 2239842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2249842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, 2259842ef35STrond Myklebust rpci->ops->destroy_msg, -EAGAIN); 2269842ef35STrond Myklebust } 2279842ef35STrond Myklebust } 228e712804aS\"J. Bruce Fields\ last_close = rpci->nwriters == 0 && rpci->nreaders == 0; 229e712804aS\"J. Bruce Fields\ if (last_close && rpci->ops->release_pipe) 2301da177e4SLinus Torvalds rpci->ops->release_pipe(inode); 2311da177e4SLinus Torvalds out: 2321b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2331da177e4SLinus Torvalds return 0; 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds static ssize_t 2371da177e4SLinus Torvalds rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) 2381da177e4SLinus Torvalds { 239303b46bbSJosef Sipek struct inode *inode = filp->f_path.dentry->d_inode; 2401da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 2411da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 2421da177e4SLinus Torvalds int res = 0; 2431da177e4SLinus Torvalds 2441b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2451da177e4SLinus Torvalds if (rpci->ops == NULL) { 2461da177e4SLinus Torvalds res = -EPIPE; 2471da177e4SLinus Torvalds goto out_unlock; 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds msg = filp->private_data; 2501da177e4SLinus Torvalds if (msg == NULL) { 2519842ef35STrond Myklebust spin_lock(&inode->i_lock); 2521da177e4SLinus Torvalds if (!list_empty(&rpci->pipe)) { 2531da177e4SLinus Torvalds msg = list_entry(rpci->pipe.next, 2541da177e4SLinus Torvalds struct rpc_pipe_msg, 2551da177e4SLinus Torvalds list); 2561da177e4SLinus Torvalds list_move(&msg->list, &rpci->in_upcall); 2571da177e4SLinus Torvalds rpci->pipelen -= msg->len; 2581da177e4SLinus Torvalds filp->private_data = msg; 2591da177e4SLinus Torvalds msg->copied = 0; 2601da177e4SLinus Torvalds } 2619842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2621da177e4SLinus Torvalds if (msg == NULL) 2631da177e4SLinus Torvalds goto out_unlock; 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds /* NOTE: it is up to the callback to update msg->copied */ 2661da177e4SLinus Torvalds res = rpci->ops->upcall(filp, msg, buf, len); 2671da177e4SLinus Torvalds if (res < 0 || msg->len == msg->copied) { 2681da177e4SLinus Torvalds filp->private_data = NULL; 2699842ef35STrond Myklebust spin_lock(&inode->i_lock); 2709842ef35STrond Myklebust list_del(&msg->list); 2719842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2721da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds out_unlock: 2751b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2761da177e4SLinus Torvalds return res; 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds static ssize_t 2801da177e4SLinus Torvalds rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) 2811da177e4SLinus Torvalds { 282303b46bbSJosef Sipek struct inode *inode = filp->f_path.dentry->d_inode; 2831da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 2841da177e4SLinus Torvalds int res; 2851da177e4SLinus Torvalds 2861b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2871da177e4SLinus Torvalds res = -EPIPE; 2881da177e4SLinus Torvalds if (rpci->ops != NULL) 2891da177e4SLinus Torvalds res = rpci->ops->downcall(filp, buf, len); 2901b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2911da177e4SLinus Torvalds return res; 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds static unsigned int 2951da177e4SLinus Torvalds rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds struct rpc_inode *rpci; 2981da177e4SLinus Torvalds unsigned int mask = 0; 2991da177e4SLinus Torvalds 300303b46bbSJosef Sipek rpci = RPC_I(filp->f_path.dentry->d_inode); 3011da177e4SLinus Torvalds poll_wait(filp, &rpci->waitq, wait); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds mask = POLLOUT | POLLWRNORM; 3041da177e4SLinus Torvalds if (rpci->ops == NULL) 3051da177e4SLinus Torvalds mask |= POLLERR | POLLHUP; 306eda4f9b7SJ. Bruce Fields if (filp->private_data || !list_empty(&rpci->pipe)) 3071da177e4SLinus Torvalds mask |= POLLIN | POLLRDNORM; 3081da177e4SLinus Torvalds return mask; 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 311a6f8dbc6SArnd Bergmann static long 312a6f8dbc6SArnd Bergmann rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 3131da177e4SLinus Torvalds { 314a6f8dbc6SArnd Bergmann struct inode *inode = filp->f_path.dentry->d_inode; 315a6f8dbc6SArnd Bergmann struct rpc_inode *rpci = RPC_I(inode); 3161da177e4SLinus Torvalds int len; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds switch (cmd) { 3191da177e4SLinus Torvalds case FIONREAD: 320a6f8dbc6SArnd Bergmann spin_lock(&inode->i_lock); 321a6f8dbc6SArnd Bergmann if (rpci->ops == NULL) { 322a6f8dbc6SArnd Bergmann spin_unlock(&inode->i_lock); 3231da177e4SLinus Torvalds return -EPIPE; 324a6f8dbc6SArnd Bergmann } 3251da177e4SLinus Torvalds len = rpci->pipelen; 3261da177e4SLinus Torvalds if (filp->private_data) { 3271da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 3281da177e4SLinus Torvalds msg = (struct rpc_pipe_msg *)filp->private_data; 3291da177e4SLinus Torvalds len += msg->len - msg->copied; 3301da177e4SLinus Torvalds } 331a6f8dbc6SArnd Bergmann spin_unlock(&inode->i_lock); 3321da177e4SLinus Torvalds return put_user(len, (int __user *)arg); 3331da177e4SLinus Torvalds default: 3341da177e4SLinus Torvalds return -EINVAL; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 338da7071d7SArjan van de Ven static const struct file_operations rpc_pipe_fops = { 3391da177e4SLinus Torvalds .owner = THIS_MODULE, 3401da177e4SLinus Torvalds .llseek = no_llseek, 3411da177e4SLinus Torvalds .read = rpc_pipe_read, 3421da177e4SLinus Torvalds .write = rpc_pipe_write, 3431da177e4SLinus Torvalds .poll = rpc_pipe_poll, 344674b604cSFrederic Weisbecker .unlocked_ioctl = rpc_pipe_ioctl, 3451da177e4SLinus Torvalds .open = rpc_pipe_open, 3461da177e4SLinus Torvalds .release = rpc_pipe_release, 3471da177e4SLinus Torvalds }; 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds static int 3501da177e4SLinus Torvalds rpc_show_info(struct seq_file *m, void *v) 3511da177e4SLinus Torvalds { 3521da177e4SLinus Torvalds struct rpc_clnt *clnt = m->private; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds seq_printf(m, "RPC server: %s\n", clnt->cl_server); 3551da177e4SLinus Torvalds seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, 3561da177e4SLinus Torvalds clnt->cl_prog, clnt->cl_vers); 357e7f78657SChuck Lever seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); 358e7f78657SChuck Lever seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); 359bf19aaceSJ. Bruce Fields seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); 3601da177e4SLinus Torvalds return 0; 3611da177e4SLinus Torvalds } 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds static int 3641da177e4SLinus Torvalds rpc_info_open(struct inode *inode, struct file *file) 3651da177e4SLinus Torvalds { 3661da177e4SLinus Torvalds struct rpc_clnt *clnt; 3671da177e4SLinus Torvalds int ret = single_open(file, rpc_show_info, NULL); 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds if (!ret) { 3701da177e4SLinus Torvalds struct seq_file *m = file->private_data; 3711b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 3721da177e4SLinus Torvalds clnt = RPC_I(inode)->private; 3731da177e4SLinus Torvalds if (clnt) { 37434f52e35STrond Myklebust kref_get(&clnt->cl_kref); 3751da177e4SLinus Torvalds m->private = clnt; 3761da177e4SLinus Torvalds } else { 3771da177e4SLinus Torvalds single_release(inode, file); 3781da177e4SLinus Torvalds ret = -EINVAL; 3791da177e4SLinus Torvalds } 3801b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 3811da177e4SLinus Torvalds } 3821da177e4SLinus Torvalds return ret; 3831da177e4SLinus Torvalds } 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds static int 3861da177e4SLinus Torvalds rpc_info_release(struct inode *inode, struct file *file) 3871da177e4SLinus Torvalds { 3881da177e4SLinus Torvalds struct seq_file *m = file->private_data; 3891da177e4SLinus Torvalds struct rpc_clnt *clnt = (struct rpc_clnt *)m->private; 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds if (clnt) 3921da177e4SLinus Torvalds rpc_release_client(clnt); 3931da177e4SLinus Torvalds return single_release(inode, file); 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds 396da7071d7SArjan van de Ven static const struct file_operations rpc_info_operations = { 3971da177e4SLinus Torvalds .owner = THIS_MODULE, 3981da177e4SLinus Torvalds .open = rpc_info_open, 3991da177e4SLinus Torvalds .read = seq_read, 4001da177e4SLinus Torvalds .llseek = seq_lseek, 4011da177e4SLinus Torvalds .release = rpc_info_release, 4021da177e4SLinus Torvalds }; 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds /* 4061da177e4SLinus Torvalds * Description of fs contents. 4071da177e4SLinus Torvalds */ 4081da177e4SLinus Torvalds struct rpc_filelist { 409ac6feceeSTrond Myklebust const char *name; 41099ac48f5SArjan van de Ven const struct file_operations *i_fop; 4117364af6aSTrond Myklebust umode_t mode; 4121da177e4SLinus Torvalds }; 4131da177e4SLinus Torvalds 41454281548STrond Myklebust struct vfsmount *rpc_get_mount(void) 4151da177e4SLinus Torvalds { 41654281548STrond Myklebust int err; 41754281548STrond Myklebust 4181f5ce9e9STrond Myklebust err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mount, &rpc_mount_count); 41954281548STrond Myklebust if (err != 0) 42054281548STrond Myklebust return ERR_PTR(err); 42154281548STrond Myklebust return rpc_mount; 4221da177e4SLinus Torvalds } 423e571cbf1STrond Myklebust EXPORT_SYMBOL_GPL(rpc_get_mount); 4241da177e4SLinus Torvalds 42554281548STrond Myklebust void rpc_put_mount(void) 4261da177e4SLinus Torvalds { 4271da177e4SLinus Torvalds simple_release_fs(&rpc_mount, &rpc_mount_count); 4281da177e4SLinus Torvalds } 429e571cbf1STrond Myklebust EXPORT_SYMBOL_GPL(rpc_put_mount); 4301da177e4SLinus Torvalds 43162e1761cSTrond Myklebust static int rpc_delete_dentry(struct dentry *dentry) 43262e1761cSTrond Myklebust { 43362e1761cSTrond Myklebust return 1; 43462e1761cSTrond Myklebust } 43562e1761cSTrond Myklebust 4363ba13d17SAl Viro static const struct dentry_operations rpc_dentry_operations = { 43762e1761cSTrond Myklebust .d_delete = rpc_delete_dentry, 43862e1761cSTrond Myklebust }; 43962e1761cSTrond Myklebust 4401da177e4SLinus Torvalds static struct inode * 4417364af6aSTrond Myklebust rpc_get_inode(struct super_block *sb, umode_t mode) 4421da177e4SLinus Torvalds { 4431da177e4SLinus Torvalds struct inode *inode = new_inode(sb); 4441da177e4SLinus Torvalds if (!inode) 4451da177e4SLinus Torvalds return NULL; 4461da177e4SLinus Torvalds inode->i_mode = mode; 4471da177e4SLinus Torvalds inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 4481da177e4SLinus Torvalds switch(mode & S_IFMT) { 4491da177e4SLinus Torvalds case S_IFDIR: 4501da177e4SLinus Torvalds inode->i_fop = &simple_dir_operations; 4511da177e4SLinus Torvalds inode->i_op = &simple_dir_inode_operations; 452d8c76e6fSDave Hansen inc_nlink(inode); 4531da177e4SLinus Torvalds default: 4541da177e4SLinus Torvalds break; 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds return inode; 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds 4597589806eSTrond Myklebust static int __rpc_create_common(struct inode *dir, struct dentry *dentry, 4607589806eSTrond Myklebust umode_t mode, 4617589806eSTrond Myklebust const struct file_operations *i_fop, 4627589806eSTrond Myklebust void *private) 4637589806eSTrond Myklebust { 4647589806eSTrond Myklebust struct inode *inode; 4657589806eSTrond Myklebust 4667589806eSTrond Myklebust BUG_ON(!d_unhashed(dentry)); 4677589806eSTrond Myklebust inode = rpc_get_inode(dir->i_sb, mode); 4687589806eSTrond Myklebust if (!inode) 4697589806eSTrond Myklebust goto out_err; 4707589806eSTrond Myklebust inode->i_ino = iunique(dir->i_sb, 100); 4717589806eSTrond Myklebust if (i_fop) 4727589806eSTrond Myklebust inode->i_fop = i_fop; 4737589806eSTrond Myklebust if (private) 4747589806eSTrond Myklebust rpc_inode_setowner(inode, private); 4757589806eSTrond Myklebust d_add(dentry, inode); 4767589806eSTrond Myklebust return 0; 4777589806eSTrond Myklebust out_err: 4787589806eSTrond Myklebust printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", 4797589806eSTrond Myklebust __FILE__, __func__, dentry->d_name.name); 4807589806eSTrond Myklebust dput(dentry); 4817589806eSTrond Myklebust return -ENOMEM; 4827589806eSTrond Myklebust } 4837589806eSTrond Myklebust 484ac6feceeSTrond Myklebust static int __rpc_create(struct inode *dir, struct dentry *dentry, 485ac6feceeSTrond Myklebust umode_t mode, 486ac6feceeSTrond Myklebust const struct file_operations *i_fop, 487ac6feceeSTrond Myklebust void *private) 488ac6feceeSTrond Myklebust { 489ac6feceeSTrond Myklebust int err; 490ac6feceeSTrond Myklebust 491ac6feceeSTrond Myklebust err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private); 492ac6feceeSTrond Myklebust if (err) 493ac6feceeSTrond Myklebust return err; 494ac6feceeSTrond Myklebust fsnotify_create(dir, dentry); 495ac6feceeSTrond Myklebust return 0; 496ac6feceeSTrond Myklebust } 497ac6feceeSTrond Myklebust 4987589806eSTrond Myklebust static int __rpc_mkdir(struct inode *dir, struct dentry *dentry, 4997589806eSTrond Myklebust umode_t mode, 5007589806eSTrond Myklebust const struct file_operations *i_fop, 5017589806eSTrond Myklebust void *private) 5027589806eSTrond Myklebust { 5037589806eSTrond Myklebust int err; 5047589806eSTrond Myklebust 5057589806eSTrond Myklebust err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private); 5067589806eSTrond Myklebust if (err) 5077589806eSTrond Myklebust return err; 5087589806eSTrond Myklebust inc_nlink(dir); 5097589806eSTrond Myklebust fsnotify_mkdir(dir, dentry); 5107589806eSTrond Myklebust return 0; 5117589806eSTrond Myklebust } 5127589806eSTrond Myklebust 5137589806eSTrond Myklebust static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, 5147589806eSTrond Myklebust umode_t mode, 5157589806eSTrond Myklebust const struct file_operations *i_fop, 5167589806eSTrond Myklebust void *private, 5177589806eSTrond Myklebust const struct rpc_pipe_ops *ops, 5187589806eSTrond Myklebust int flags) 5197589806eSTrond Myklebust { 5207589806eSTrond Myklebust struct rpc_inode *rpci; 5217589806eSTrond Myklebust int err; 5227589806eSTrond Myklebust 5237589806eSTrond Myklebust err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private); 5247589806eSTrond Myklebust if (err) 5257589806eSTrond Myklebust return err; 5267589806eSTrond Myklebust rpci = RPC_I(dentry->d_inode); 5277589806eSTrond Myklebust rpci->nkern_readwriters = 1; 5287589806eSTrond Myklebust rpci->private = private; 5297589806eSTrond Myklebust rpci->flags = flags; 5307589806eSTrond Myklebust rpci->ops = ops; 5317589806eSTrond Myklebust fsnotify_create(dir, dentry); 5327589806eSTrond Myklebust return 0; 5337589806eSTrond Myklebust } 5347589806eSTrond Myklebust 535ac6feceeSTrond Myklebust static int __rpc_rmdir(struct inode *dir, struct dentry *dentry) 536ac6feceeSTrond Myklebust { 537ac6feceeSTrond Myklebust int ret; 538ac6feceeSTrond Myklebust 539ac6feceeSTrond Myklebust dget(dentry); 540ac6feceeSTrond Myklebust ret = simple_rmdir(dir, dentry); 541ac6feceeSTrond Myklebust d_delete(dentry); 542ac6feceeSTrond Myklebust dput(dentry); 543ac6feceeSTrond Myklebust return ret; 544ac6feceeSTrond Myklebust } 545ac6feceeSTrond Myklebust 546810d90bcSTrond Myklebust static int __rpc_unlink(struct inode *dir, struct dentry *dentry) 547810d90bcSTrond Myklebust { 548810d90bcSTrond Myklebust int ret; 549810d90bcSTrond Myklebust 550810d90bcSTrond Myklebust dget(dentry); 551810d90bcSTrond Myklebust ret = simple_unlink(dir, dentry); 552810d90bcSTrond Myklebust d_delete(dentry); 553810d90bcSTrond Myklebust dput(dentry); 554810d90bcSTrond Myklebust return ret; 555810d90bcSTrond Myklebust } 556810d90bcSTrond Myklebust 557810d90bcSTrond Myklebust static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry) 558810d90bcSTrond Myklebust { 559810d90bcSTrond Myklebust struct inode *inode = dentry->d_inode; 560810d90bcSTrond Myklebust struct rpc_inode *rpci = RPC_I(inode); 561810d90bcSTrond Myklebust 562810d90bcSTrond Myklebust rpci->nkern_readwriters--; 563810d90bcSTrond Myklebust if (rpci->nkern_readwriters != 0) 564810d90bcSTrond Myklebust return 0; 565810d90bcSTrond Myklebust rpc_close_pipes(inode); 566810d90bcSTrond Myklebust return __rpc_unlink(dir, dentry); 567810d90bcSTrond Myklebust } 568810d90bcSTrond Myklebust 569cfeaa4a3STrond Myklebust static struct dentry *__rpc_lookup_create(struct dentry *parent, 570cfeaa4a3STrond Myklebust struct qstr *name) 571cfeaa4a3STrond Myklebust { 572cfeaa4a3STrond Myklebust struct dentry *dentry; 573cfeaa4a3STrond Myklebust 574cfeaa4a3STrond Myklebust dentry = d_lookup(parent, name); 575cfeaa4a3STrond Myklebust if (!dentry) { 576cfeaa4a3STrond Myklebust dentry = d_alloc(parent, name); 577cfeaa4a3STrond Myklebust if (!dentry) { 578cfeaa4a3STrond Myklebust dentry = ERR_PTR(-ENOMEM); 579cfeaa4a3STrond Myklebust goto out_err; 580cfeaa4a3STrond Myklebust } 581cfeaa4a3STrond Myklebust } 582cfeaa4a3STrond Myklebust if (!dentry->d_inode) 583cfeaa4a3STrond Myklebust dentry->d_op = &rpc_dentry_operations; 584cfeaa4a3STrond Myklebust out_err: 585cfeaa4a3STrond Myklebust return dentry; 586cfeaa4a3STrond Myklebust } 587cfeaa4a3STrond Myklebust 588cfeaa4a3STrond Myklebust static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, 589cfeaa4a3STrond Myklebust struct qstr *name) 590cfeaa4a3STrond Myklebust { 591cfeaa4a3STrond Myklebust struct dentry *dentry; 592cfeaa4a3STrond Myklebust 593cfeaa4a3STrond Myklebust dentry = __rpc_lookup_create(parent, name); 594f1f0abe1SDan Carpenter if (IS_ERR(dentry)) 595f1f0abe1SDan Carpenter return dentry; 596cfeaa4a3STrond Myklebust if (dentry->d_inode == NULL) 597cfeaa4a3STrond Myklebust return dentry; 598cfeaa4a3STrond Myklebust dput(dentry); 599cfeaa4a3STrond Myklebust return ERR_PTR(-EEXIST); 600cfeaa4a3STrond Myklebust } 601cfeaa4a3STrond Myklebust 6021da177e4SLinus Torvalds /* 6031da177e4SLinus Torvalds * FIXME: This probably has races. 6041da177e4SLinus Torvalds */ 605ac6feceeSTrond Myklebust static void __rpc_depopulate(struct dentry *parent, 606ac6feceeSTrond Myklebust const struct rpc_filelist *files, 607ac6feceeSTrond Myklebust int start, int eof) 6081da177e4SLinus Torvalds { 6091da177e4SLinus Torvalds struct inode *dir = parent->d_inode; 610ac6feceeSTrond Myklebust struct dentry *dentry; 611ac6feceeSTrond Myklebust struct qstr name; 612ac6feceeSTrond Myklebust int i; 613ac6feceeSTrond Myklebust 614ac6feceeSTrond Myklebust for (i = start; i < eof; i++) { 615ac6feceeSTrond Myklebust name.name = files[i].name; 616ac6feceeSTrond Myklebust name.len = strlen(files[i].name); 617ac6feceeSTrond Myklebust name.hash = full_name_hash(name.name, name.len); 618ac6feceeSTrond Myklebust dentry = d_lookup(parent, &name); 619ac6feceeSTrond Myklebust 620ac6feceeSTrond Myklebust if (dentry == NULL) 621ac6feceeSTrond Myklebust continue; 622ac6feceeSTrond Myklebust if (dentry->d_inode == NULL) 623ac6feceeSTrond Myklebust goto next; 624ac6feceeSTrond Myklebust switch (dentry->d_inode->i_mode & S_IFMT) { 625ac6feceeSTrond Myklebust default: 626ac6feceeSTrond Myklebust BUG(); 627ac6feceeSTrond Myklebust case S_IFREG: 628ac6feceeSTrond Myklebust __rpc_unlink(dir, dentry); 629ac6feceeSTrond Myklebust break; 630ac6feceeSTrond Myklebust case S_IFDIR: 631ac6feceeSTrond Myklebust __rpc_rmdir(dir, dentry); 632ac6feceeSTrond Myklebust } 633ac6feceeSTrond Myklebust next: 634ac6feceeSTrond Myklebust dput(dentry); 635ac6feceeSTrond Myklebust } 636ac6feceeSTrond Myklebust } 637ac6feceeSTrond Myklebust 638ac6feceeSTrond Myklebust static void rpc_depopulate(struct dentry *parent, 639ac6feceeSTrond Myklebust const struct rpc_filelist *files, 640ac6feceeSTrond Myklebust int start, int eof) 641ac6feceeSTrond Myklebust { 642ac6feceeSTrond Myklebust struct inode *dir = parent->d_inode; 6431da177e4SLinus Torvalds 644c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD); 645ac6feceeSTrond Myklebust __rpc_depopulate(parent, files, start, eof); 6461b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 649ac6feceeSTrond Myklebust static int rpc_populate(struct dentry *parent, 650ac6feceeSTrond Myklebust const struct rpc_filelist *files, 651ac6feceeSTrond Myklebust int start, int eof, 652ac6feceeSTrond Myklebust void *private) 6531da177e4SLinus Torvalds { 654ac6feceeSTrond Myklebust struct inode *dir = parent->d_inode; 6551da177e4SLinus Torvalds struct dentry *dentry; 656ac6feceeSTrond Myklebust int i, err; 6571da177e4SLinus Torvalds 6581b1dcc1bSJes Sorensen mutex_lock(&dir->i_mutex); 6591da177e4SLinus Torvalds for (i = start; i < eof; i++) { 660ac6feceeSTrond Myklebust struct qstr q; 661ac6feceeSTrond Myklebust 662ac6feceeSTrond Myklebust q.name = files[i].name; 663ac6feceeSTrond Myklebust q.len = strlen(files[i].name); 664ac6feceeSTrond Myklebust q.hash = full_name_hash(q.name, q.len); 665ac6feceeSTrond Myklebust dentry = __rpc_lookup_create_exclusive(parent, &q); 666ac6feceeSTrond Myklebust err = PTR_ERR(dentry); 667ac6feceeSTrond Myklebust if (IS_ERR(dentry)) 6681da177e4SLinus Torvalds goto out_bad; 669ac6feceeSTrond Myklebust switch (files[i].mode & S_IFMT) { 670ac6feceeSTrond Myklebust default: 671ac6feceeSTrond Myklebust BUG(); 672ac6feceeSTrond Myklebust case S_IFREG: 673ac6feceeSTrond Myklebust err = __rpc_create(dir, dentry, 674ac6feceeSTrond Myklebust files[i].mode, 675ac6feceeSTrond Myklebust files[i].i_fop, 676ac6feceeSTrond Myklebust private); 677ac6feceeSTrond Myklebust break; 678ac6feceeSTrond Myklebust case S_IFDIR: 679ac6feceeSTrond Myklebust err = __rpc_mkdir(dir, dentry, 680ac6feceeSTrond Myklebust files[i].mode, 681ac6feceeSTrond Myklebust NULL, 682ac6feceeSTrond Myklebust private); 6831da177e4SLinus Torvalds } 684ac6feceeSTrond Myklebust if (err != 0) 685ac6feceeSTrond Myklebust goto out_bad; 6861da177e4SLinus Torvalds } 6871b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 6881da177e4SLinus Torvalds return 0; 6891da177e4SLinus Torvalds out_bad: 690ac6feceeSTrond Myklebust __rpc_depopulate(parent, files, start, eof); 6911b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 6921da177e4SLinus Torvalds printk(KERN_WARNING "%s: %s failed to populate directory %s\n", 6930dc47877SHarvey Harrison __FILE__, __func__, parent->d_name.name); 694ac6feceeSTrond Myklebust return err; 695f134585aSTrond Myklebust } 696f134585aSTrond Myklebust 697e57aed77STrond Myklebust static struct dentry *rpc_mkdir_populate(struct dentry *parent, 698e57aed77STrond Myklebust struct qstr *name, umode_t mode, void *private, 699e57aed77STrond Myklebust int (*populate)(struct dentry *, void *), void *args_populate) 700f134585aSTrond Myklebust { 701f134585aSTrond Myklebust struct dentry *dentry; 7027d59d1e8STrond Myklebust struct inode *dir = parent->d_inode; 703f134585aSTrond Myklebust int error; 704f134585aSTrond Myklebust 7057d59d1e8STrond Myklebust mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 7067d59d1e8STrond Myklebust dentry = __rpc_lookup_create_exclusive(parent, name); 707f134585aSTrond Myklebust if (IS_ERR(dentry)) 7087d59d1e8STrond Myklebust goto out; 7097d59d1e8STrond Myklebust error = __rpc_mkdir(dir, dentry, mode, NULL, private); 7107589806eSTrond Myklebust if (error != 0) 7117589806eSTrond Myklebust goto out_err; 712e57aed77STrond Myklebust if (populate != NULL) { 713e57aed77STrond Myklebust error = populate(dentry, args_populate); 714f134585aSTrond Myklebust if (error) 715ac6feceeSTrond Myklebust goto err_rmdir; 716e57aed77STrond Myklebust } 717f134585aSTrond Myklebust out: 7181b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 7195c3e985aSTrond Myklebust return dentry; 720ac6feceeSTrond Myklebust err_rmdir: 721f134585aSTrond Myklebust __rpc_rmdir(dir, dentry); 7227589806eSTrond Myklebust out_err: 723f134585aSTrond Myklebust dentry = ERR_PTR(error); 724f134585aSTrond Myklebust goto out; 725f134585aSTrond Myklebust } 726f134585aSTrond Myklebust 727e57aed77STrond Myklebust static int rpc_rmdir_depopulate(struct dentry *dentry, 728e57aed77STrond Myklebust void (*depopulate)(struct dentry *)) 729f134585aSTrond Myklebust { 730dff02cc1STrond Myklebust struct dentry *parent; 731f134585aSTrond Myklebust struct inode *dir; 732f134585aSTrond Myklebust int error; 733f134585aSTrond Myklebust 734dff02cc1STrond Myklebust parent = dget_parent(dentry); 735dff02cc1STrond Myklebust dir = parent->d_inode; 736c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 737e57aed77STrond Myklebust if (depopulate != NULL) 738e57aed77STrond Myklebust depopulate(dentry); 739f134585aSTrond Myklebust error = __rpc_rmdir(dir, dentry); 7401b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 741dff02cc1STrond Myklebust dput(parent); 742f134585aSTrond Myklebust return error; 743f134585aSTrond Myklebust } 7441da177e4SLinus Torvalds 74593a44a75SJ. Bruce Fields /** 74693a44a75SJ. Bruce Fields * rpc_mkpipe - make an rpc_pipefs file for kernel<->userspace communication 74793a44a75SJ. Bruce Fields * @parent: dentry of directory to create new "pipe" in 74893a44a75SJ. Bruce Fields * @name: name of pipe 74993a44a75SJ. Bruce Fields * @private: private data to associate with the pipe, for the caller's use 75093a44a75SJ. Bruce Fields * @ops: operations defining the behavior of the pipe: upcall, downcall, 751c3810608S\"J. Bruce Fields\ * release_pipe, open_pipe, and destroy_msg. 75265b6e42cSRandy Dunlap * @flags: rpc_inode flags 75393a44a75SJ. Bruce Fields * 75493a44a75SJ. Bruce Fields * Data is made available for userspace to read by calls to 75593a44a75SJ. Bruce Fields * rpc_queue_upcall(). The actual reads will result in calls to 75693a44a75SJ. Bruce Fields * @ops->upcall, which will be called with the file pointer, 75793a44a75SJ. Bruce Fields * message, and userspace buffer to copy to. 75893a44a75SJ. Bruce Fields * 75993a44a75SJ. Bruce Fields * Writes can come at any time, and do not necessarily have to be 76093a44a75SJ. Bruce Fields * responses to upcalls. They will result in calls to @msg->downcall. 76193a44a75SJ. Bruce Fields * 76293a44a75SJ. Bruce Fields * The @private argument passed here will be available to all these methods 76393a44a75SJ. Bruce Fields * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. 76493a44a75SJ. Bruce Fields */ 765b693ba4aSTrond Myklebust struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, 766b693ba4aSTrond Myklebust void *private, const struct rpc_pipe_ops *ops, 767b693ba4aSTrond Myklebust int flags) 7681da177e4SLinus Torvalds { 7691da177e4SLinus Torvalds struct dentry *dentry; 7707589806eSTrond Myklebust struct inode *dir = parent->d_inode; 7717364af6aSTrond Myklebust umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR; 772cfeaa4a3STrond Myklebust struct qstr q; 7737589806eSTrond Myklebust int err; 7747364af6aSTrond Myklebust 7757364af6aSTrond Myklebust if (ops->upcall == NULL) 7767364af6aSTrond Myklebust umode &= ~S_IRUGO; 7777364af6aSTrond Myklebust if (ops->downcall == NULL) 7787364af6aSTrond Myklebust umode &= ~S_IWUGO; 7791da177e4SLinus Torvalds 780cfeaa4a3STrond Myklebust q.name = name; 781cfeaa4a3STrond Myklebust q.len = strlen(name); 782cfeaa4a3STrond Myklebust q.hash = full_name_hash(q.name, q.len), 783cfeaa4a3STrond Myklebust 784cfeaa4a3STrond Myklebust mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 785cfeaa4a3STrond Myklebust dentry = __rpc_lookup_create(parent, &q); 7861da177e4SLinus Torvalds if (IS_ERR(dentry)) 787cfeaa4a3STrond Myklebust goto out; 78834f30896STrond Myklebust if (dentry->d_inode) { 7897589806eSTrond Myklebust struct rpc_inode *rpci = RPC_I(dentry->d_inode); 79034f30896STrond Myklebust if (rpci->private != private || 79134f30896STrond Myklebust rpci->ops != ops || 79234f30896STrond Myklebust rpci->flags != flags) { 79334f30896STrond Myklebust dput (dentry); 794810d90bcSTrond Myklebust err = -EBUSY; 795810d90bcSTrond Myklebust goto out_err; 79634f30896STrond Myklebust } 79703a1256fSTrond Myklebust rpci->nkern_readwriters++; 79834f30896STrond Myklebust goto out; 79934f30896STrond Myklebust } 8007589806eSTrond Myklebust 8017589806eSTrond Myklebust err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops, 8027589806eSTrond Myklebust private, ops, flags); 8037589806eSTrond Myklebust if (err) 8047589806eSTrond Myklebust goto out_err; 805f134585aSTrond Myklebust out: 8061b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 8075c3e985aSTrond Myklebust return dentry; 8087589806eSTrond Myklebust out_err: 8097589806eSTrond Myklebust dentry = ERR_PTR(err); 810158998b6STrond Myklebust printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", 8110dc47877SHarvey Harrison __FILE__, __func__, parent->d_name.name, name, 8127589806eSTrond Myklebust err); 813f134585aSTrond Myklebust goto out; 8141da177e4SLinus Torvalds } 815468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_mkpipe); 8161da177e4SLinus Torvalds 81793a44a75SJ. Bruce Fields /** 81893a44a75SJ. Bruce Fields * rpc_unlink - remove a pipe 81993a44a75SJ. Bruce Fields * @dentry: dentry for the pipe, as returned from rpc_mkpipe 82093a44a75SJ. Bruce Fields * 82193a44a75SJ. Bruce Fields * After this call, lookups will no longer find the pipe, and any 82293a44a75SJ. Bruce Fields * attempts to read or write using preexisting opens of the pipe will 82393a44a75SJ. Bruce Fields * return -EPIPE. 82493a44a75SJ. Bruce Fields */ 825f134585aSTrond Myklebust int 8265d67476fSTrond Myklebust rpc_unlink(struct dentry *dentry) 8271da177e4SLinus Torvalds { 8285d67476fSTrond Myklebust struct dentry *parent; 829f134585aSTrond Myklebust struct inode *dir; 8305d67476fSTrond Myklebust int error = 0; 8311da177e4SLinus Torvalds 8325d67476fSTrond Myklebust parent = dget_parent(dentry); 8335d67476fSTrond Myklebust dir = parent->d_inode; 834c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 835810d90bcSTrond Myklebust error = __rpc_rmpipe(dir, dentry); 8361b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 8375d67476fSTrond Myklebust dput(parent); 838f134585aSTrond Myklebust return error; 8391da177e4SLinus Torvalds } 840468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_unlink); 8411da177e4SLinus Torvalds 842e57aed77STrond Myklebust enum { 843e57aed77STrond Myklebust RPCAUTH_info, 844e57aed77STrond Myklebust RPCAUTH_EOF 845e57aed77STrond Myklebust }; 846e57aed77STrond Myklebust 847e57aed77STrond Myklebust static const struct rpc_filelist authfiles[] = { 848e57aed77STrond Myklebust [RPCAUTH_info] = { 849e57aed77STrond Myklebust .name = "info", 850e57aed77STrond Myklebust .i_fop = &rpc_info_operations, 851e57aed77STrond Myklebust .mode = S_IFREG | S_IRUSR, 852e57aed77STrond Myklebust }, 853e57aed77STrond Myklebust }; 854e57aed77STrond Myklebust 855e57aed77STrond Myklebust static int rpc_clntdir_populate(struct dentry *dentry, void *private) 856e57aed77STrond Myklebust { 857e57aed77STrond Myklebust return rpc_populate(dentry, 858e57aed77STrond Myklebust authfiles, RPCAUTH_info, RPCAUTH_EOF, 859e57aed77STrond Myklebust private); 860e57aed77STrond Myklebust } 861e57aed77STrond Myklebust 862e57aed77STrond Myklebust static void rpc_clntdir_depopulate(struct dentry *dentry) 863e57aed77STrond Myklebust { 864e57aed77STrond Myklebust rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF); 865e57aed77STrond Myklebust } 866e57aed77STrond Myklebust 8677d59d1e8STrond Myklebust /** 8687d59d1e8STrond Myklebust * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs 8694111d4fdSRandy Dunlap * @dentry: dentry from the rpc_pipefs root to the new directory 8704111d4fdSRandy Dunlap * @name: &struct qstr for the name 8717d59d1e8STrond Myklebust * @rpc_client: rpc client to associate with this directory 8727d59d1e8STrond Myklebust * 8737d59d1e8STrond Myklebust * This creates a directory at the given @path associated with 8747d59d1e8STrond Myklebust * @rpc_clnt, which will contain a file named "info" with some basic 8757d59d1e8STrond Myklebust * information about the client, together with any "pipes" that may 8767d59d1e8STrond Myklebust * later be created using rpc_mkpipe(). 8777d59d1e8STrond Myklebust */ 87823ac6581STrond Myklebust struct dentry *rpc_create_client_dir(struct dentry *dentry, 87923ac6581STrond Myklebust struct qstr *name, 8807d59d1e8STrond Myklebust struct rpc_clnt *rpc_client) 8817d59d1e8STrond Myklebust { 882e57aed77STrond Myklebust return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL, 883e57aed77STrond Myklebust rpc_clntdir_populate, rpc_client); 884e57aed77STrond Myklebust } 885e57aed77STrond Myklebust 886e57aed77STrond Myklebust /** 887e57aed77STrond Myklebust * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() 888e57aed77STrond Myklebust * @dentry: directory to remove 889e57aed77STrond Myklebust */ 890e57aed77STrond Myklebust int rpc_remove_client_dir(struct dentry *dentry) 891e57aed77STrond Myklebust { 892e57aed77STrond Myklebust return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate); 8937d59d1e8STrond Myklebust } 8947d59d1e8STrond Myklebust 8958854e82dSTrond Myklebust static const struct rpc_filelist cache_pipefs_files[3] = { 8968854e82dSTrond Myklebust [0] = { 8978854e82dSTrond Myklebust .name = "channel", 8988854e82dSTrond Myklebust .i_fop = &cache_file_operations_pipefs, 89996c61cbdSTrond Myklebust .mode = S_IFREG|S_IRUSR|S_IWUSR, 9008854e82dSTrond Myklebust }, 9018854e82dSTrond Myklebust [1] = { 9028854e82dSTrond Myklebust .name = "content", 9038854e82dSTrond Myklebust .i_fop = &content_file_operations_pipefs, 9048854e82dSTrond Myklebust .mode = S_IFREG|S_IRUSR, 9058854e82dSTrond Myklebust }, 9068854e82dSTrond Myklebust [2] = { 9078854e82dSTrond Myklebust .name = "flush", 9088854e82dSTrond Myklebust .i_fop = &cache_flush_operations_pipefs, 9098854e82dSTrond Myklebust .mode = S_IFREG|S_IRUSR|S_IWUSR, 9108854e82dSTrond Myklebust }, 9118854e82dSTrond Myklebust }; 9128854e82dSTrond Myklebust 9138854e82dSTrond Myklebust static int rpc_cachedir_populate(struct dentry *dentry, void *private) 9148854e82dSTrond Myklebust { 9158854e82dSTrond Myklebust return rpc_populate(dentry, 9168854e82dSTrond Myklebust cache_pipefs_files, 0, 3, 9178854e82dSTrond Myklebust private); 9188854e82dSTrond Myklebust } 9198854e82dSTrond Myklebust 9208854e82dSTrond Myklebust static void rpc_cachedir_depopulate(struct dentry *dentry) 9218854e82dSTrond Myklebust { 9228854e82dSTrond Myklebust rpc_depopulate(dentry, cache_pipefs_files, 0, 3); 9238854e82dSTrond Myklebust } 9248854e82dSTrond Myklebust 9258854e82dSTrond Myklebust struct dentry *rpc_create_cache_dir(struct dentry *parent, struct qstr *name, 9268854e82dSTrond Myklebust mode_t umode, struct cache_detail *cd) 9278854e82dSTrond Myklebust { 9288854e82dSTrond Myklebust return rpc_mkdir_populate(parent, name, umode, NULL, 9298854e82dSTrond Myklebust rpc_cachedir_populate, cd); 9308854e82dSTrond Myklebust } 9318854e82dSTrond Myklebust 9328854e82dSTrond Myklebust void rpc_remove_cache_dir(struct dentry *dentry) 9338854e82dSTrond Myklebust { 9348854e82dSTrond Myklebust rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate); 9358854e82dSTrond Myklebust } 9368854e82dSTrond Myklebust 9371da177e4SLinus Torvalds /* 9381da177e4SLinus Torvalds * populate the filesystem 9391da177e4SLinus Torvalds */ 940b87221deSAlexey Dobriyan static const struct super_operations s_ops = { 9411da177e4SLinus Torvalds .alloc_inode = rpc_alloc_inode, 9421da177e4SLinus Torvalds .destroy_inode = rpc_destroy_inode, 9431da177e4SLinus Torvalds .statfs = simple_statfs, 9441da177e4SLinus Torvalds }; 9451da177e4SLinus Torvalds 9461da177e4SLinus Torvalds #define RPCAUTH_GSSMAGIC 0x67596969 9471da177e4SLinus Torvalds 948bb156749STrond Myklebust /* 949bb156749STrond Myklebust * We have a single directory with 1 node in it. 950bb156749STrond Myklebust */ 951bb156749STrond Myklebust enum { 952bb156749STrond Myklebust RPCAUTH_lockd, 953bb156749STrond Myklebust RPCAUTH_mount, 954bb156749STrond Myklebust RPCAUTH_nfs, 955bb156749STrond Myklebust RPCAUTH_portmap, 956bb156749STrond Myklebust RPCAUTH_statd, 957bb156749STrond Myklebust RPCAUTH_nfsd4_cb, 958e571cbf1STrond Myklebust RPCAUTH_cache, 959bb156749STrond Myklebust RPCAUTH_RootEOF 960bb156749STrond Myklebust }; 961bb156749STrond Myklebust 962bb156749STrond Myklebust static const struct rpc_filelist files[] = { 963bb156749STrond Myklebust [RPCAUTH_lockd] = { 964bb156749STrond Myklebust .name = "lockd", 965bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 966bb156749STrond Myklebust }, 967bb156749STrond Myklebust [RPCAUTH_mount] = { 968bb156749STrond Myklebust .name = "mount", 969bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 970bb156749STrond Myklebust }, 971bb156749STrond Myklebust [RPCAUTH_nfs] = { 972bb156749STrond Myklebust .name = "nfs", 973bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 974bb156749STrond Myklebust }, 975bb156749STrond Myklebust [RPCAUTH_portmap] = { 976bb156749STrond Myklebust .name = "portmap", 977bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 978bb156749STrond Myklebust }, 979bb156749STrond Myklebust [RPCAUTH_statd] = { 980bb156749STrond Myklebust .name = "statd", 981bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 982bb156749STrond Myklebust }, 983bb156749STrond Myklebust [RPCAUTH_nfsd4_cb] = { 984bb156749STrond Myklebust .name = "nfsd4_cb", 985bb156749STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 986bb156749STrond Myklebust }, 987e571cbf1STrond Myklebust [RPCAUTH_cache] = { 988e571cbf1STrond Myklebust .name = "cache", 989e571cbf1STrond Myklebust .mode = S_IFDIR | S_IRUGO | S_IXUGO, 990e571cbf1STrond Myklebust }, 991bb156749STrond Myklebust }; 992bb156749STrond Myklebust 9931da177e4SLinus Torvalds static int 9941da177e4SLinus Torvalds rpc_fill_super(struct super_block *sb, void *data, int silent) 9951da177e4SLinus Torvalds { 9961da177e4SLinus Torvalds struct inode *inode; 9971da177e4SLinus Torvalds struct dentry *root; 9981da177e4SLinus Torvalds 9991da177e4SLinus Torvalds sb->s_blocksize = PAGE_CACHE_SIZE; 10001da177e4SLinus Torvalds sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 10011da177e4SLinus Torvalds sb->s_magic = RPCAUTH_GSSMAGIC; 10021da177e4SLinus Torvalds sb->s_op = &s_ops; 10031da177e4SLinus Torvalds sb->s_time_gran = 1; 10041da177e4SLinus Torvalds 10051da177e4SLinus Torvalds inode = rpc_get_inode(sb, S_IFDIR | 0755); 10061da177e4SLinus Torvalds if (!inode) 10071da177e4SLinus Torvalds return -ENOMEM; 1008fc7bed8cSAl Viro sb->s_root = root = d_alloc_root(inode); 10091da177e4SLinus Torvalds if (!root) { 10101da177e4SLinus Torvalds iput(inode); 10111da177e4SLinus Torvalds return -ENOMEM; 10121da177e4SLinus Torvalds } 1013ac6feceeSTrond Myklebust if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) 10141da177e4SLinus Torvalds return -ENOMEM; 1015fc7bed8cSAl Viro return 0; 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds 1018454e2398SDavid Howells static int 10191da177e4SLinus Torvalds rpc_get_sb(struct file_system_type *fs_type, 1020454e2398SDavid Howells int flags, const char *dev_name, void *data, struct vfsmount *mnt) 10211da177e4SLinus Torvalds { 1022454e2398SDavid Howells return get_sb_single(fs_type, flags, data, rpc_fill_super, mnt); 10231da177e4SLinus Torvalds } 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type = { 10261da177e4SLinus Torvalds .owner = THIS_MODULE, 10271da177e4SLinus Torvalds .name = "rpc_pipefs", 10281da177e4SLinus Torvalds .get_sb = rpc_get_sb, 10291da177e4SLinus Torvalds .kill_sb = kill_litter_super, 10301da177e4SLinus Torvalds }; 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds static void 103351cc5068SAlexey Dobriyan init_once(void *foo) 10341da177e4SLinus Torvalds { 10351da177e4SLinus Torvalds struct rpc_inode *rpci = (struct rpc_inode *) foo; 10361da177e4SLinus Torvalds 10371da177e4SLinus Torvalds inode_init_once(&rpci->vfs_inode); 10381da177e4SLinus Torvalds rpci->private = NULL; 10391da177e4SLinus Torvalds rpci->nreaders = 0; 10401da177e4SLinus Torvalds rpci->nwriters = 0; 10411da177e4SLinus Torvalds INIT_LIST_HEAD(&rpci->in_upcall); 10426e84c7b6STrond Myklebust INIT_LIST_HEAD(&rpci->in_downcall); 10431da177e4SLinus Torvalds INIT_LIST_HEAD(&rpci->pipe); 10441da177e4SLinus Torvalds rpci->pipelen = 0; 10451da177e4SLinus Torvalds init_waitqueue_head(&rpci->waitq); 104652bad64dSDavid Howells INIT_DELAYED_WORK(&rpci->queue_timeout, 104765f27f38SDavid Howells rpc_timeout_upcall_queue); 10481da177e4SLinus Torvalds rpci->ops = NULL; 10491da177e4SLinus Torvalds } 10501da177e4SLinus Torvalds 10511da177e4SLinus Torvalds int register_rpc_pipefs(void) 10521da177e4SLinus Torvalds { 10535bd5f581SAkinobu Mita int err; 10545bd5f581SAkinobu Mita 10551da177e4SLinus Torvalds rpc_inode_cachep = kmem_cache_create("rpc_inode_cache", 10561da177e4SLinus Torvalds sizeof(struct rpc_inode), 1057fffb60f9SPaul Jackson 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| 1058fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 105920c2df83SPaul Mundt init_once); 10601da177e4SLinus Torvalds if (!rpc_inode_cachep) 10611da177e4SLinus Torvalds return -ENOMEM; 10625bd5f581SAkinobu Mita err = register_filesystem(&rpc_pipe_fs_type); 10635bd5f581SAkinobu Mita if (err) { 10645bd5f581SAkinobu Mita kmem_cache_destroy(rpc_inode_cachep); 10655bd5f581SAkinobu Mita return err; 10665bd5f581SAkinobu Mita } 10675bd5f581SAkinobu Mita 10681da177e4SLinus Torvalds return 0; 10691da177e4SLinus Torvalds } 10701da177e4SLinus Torvalds 10711da177e4SLinus Torvalds void unregister_rpc_pipefs(void) 10721da177e4SLinus Torvalds { 10731a1d92c1SAlexey Dobriyan kmem_cache_destroy(rpc_inode_cachep); 10741da177e4SLinus Torvalds unregister_filesystem(&rpc_pipe_fs_type); 10751da177e4SLinus Torvalds } 1076