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> 291da177e4SLinus Torvalds 30ba89966cSEric Dumazet static struct vfsmount *rpc_mount __read_mostly; 311da177e4SLinus Torvalds static int rpc_mount_count; 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type; 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds 36e18b890bSChristoph Lameter static struct kmem_cache *rpc_inode_cachep __read_mostly; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds #define RPC_UPCALL_TIMEOUT (30*HZ) 391da177e4SLinus Torvalds 409842ef35STrond Myklebust static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, 419842ef35STrond Myklebust void (*destroy_msg)(struct rpc_pipe_msg *), int err) 42b3eb67a2STrond Myklebust { 43b3eb67a2STrond Myklebust struct rpc_pipe_msg *msg; 44b3eb67a2STrond Myklebust 459842ef35STrond Myklebust if (list_empty(head)) 469842ef35STrond Myklebust return; 479842ef35STrond Myklebust do { 48b3eb67a2STrond Myklebust msg = list_entry(head->next, struct rpc_pipe_msg, list); 499842ef35STrond Myklebust list_del(&msg->list); 50b3eb67a2STrond Myklebust msg->errno = err; 51b3eb67a2STrond Myklebust destroy_msg(msg); 529842ef35STrond Myklebust } while (!list_empty(head)); 531da177e4SLinus Torvalds wake_up(&rpci->waitq); 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds static void 5765f27f38SDavid Howells rpc_timeout_upcall_queue(struct work_struct *work) 581da177e4SLinus Torvalds { 599842ef35STrond Myklebust LIST_HEAD(free_list); 6065f27f38SDavid Howells struct rpc_inode *rpci = 6165f27f38SDavid Howells container_of(work, struct rpc_inode, queue_timeout.work); 621da177e4SLinus Torvalds struct inode *inode = &rpci->vfs_inode; 639842ef35STrond Myklebust void (*destroy_msg)(struct rpc_pipe_msg *); 641da177e4SLinus Torvalds 659842ef35STrond Myklebust spin_lock(&inode->i_lock); 669842ef35STrond Myklebust if (rpci->ops == NULL) { 679842ef35STrond Myklebust spin_unlock(&inode->i_lock); 689842ef35STrond Myklebust return; 699842ef35STrond Myklebust } 709842ef35STrond Myklebust destroy_msg = rpci->ops->destroy_msg; 719842ef35STrond Myklebust if (rpci->nreaders == 0) { 729842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 739842ef35STrond Myklebust rpci->pipelen = 0; 749842ef35STrond Myklebust } 759842ef35STrond Myklebust spin_unlock(&inode->i_lock); 769842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 7993a44a75SJ. Bruce Fields /** 8093a44a75SJ. Bruce Fields * rpc_queue_upcall 8193a44a75SJ. Bruce Fields * @inode: inode of upcall pipe on which to queue given message 8293a44a75SJ. Bruce Fields * @msg: message to queue 8393a44a75SJ. Bruce Fields * 8493a44a75SJ. Bruce Fields * Call with an @inode created by rpc_mkpipe() to queue an upcall. 8593a44a75SJ. Bruce Fields * A userspace process may then later read the upcall by performing a 8693a44a75SJ. Bruce Fields * read on an open file for this inode. It is up to the caller to 8793a44a75SJ. Bruce Fields * initialize the fields of @msg (other than @msg->list) appropriately. 8893a44a75SJ. Bruce Fields */ 891da177e4SLinus Torvalds int 901da177e4SLinus Torvalds rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) 911da177e4SLinus Torvalds { 921da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 936070fe6fSTrond Myklebust int res = -EPIPE; 941da177e4SLinus Torvalds 959842ef35STrond Myklebust spin_lock(&inode->i_lock); 966070fe6fSTrond Myklebust if (rpci->ops == NULL) 976070fe6fSTrond Myklebust goto out; 981da177e4SLinus Torvalds if (rpci->nreaders) { 991da177e4SLinus Torvalds list_add_tail(&msg->list, &rpci->pipe); 1001da177e4SLinus Torvalds rpci->pipelen += msg->len; 1016070fe6fSTrond Myklebust res = 0; 1021da177e4SLinus Torvalds } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) { 1031da177e4SLinus Torvalds if (list_empty(&rpci->pipe)) 10424c5d9d7STrond Myklebust queue_delayed_work(rpciod_workqueue, 10524c5d9d7STrond Myklebust &rpci->queue_timeout, 1061da177e4SLinus Torvalds RPC_UPCALL_TIMEOUT); 1071da177e4SLinus Torvalds list_add_tail(&msg->list, &rpci->pipe); 1081da177e4SLinus Torvalds rpci->pipelen += msg->len; 1096070fe6fSTrond Myklebust res = 0; 1106070fe6fSTrond Myklebust } 1116070fe6fSTrond Myklebust out: 1129842ef35STrond Myklebust spin_unlock(&inode->i_lock); 1131da177e4SLinus Torvalds wake_up(&rpci->waitq); 1141da177e4SLinus Torvalds return res; 1151da177e4SLinus Torvalds } 116468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_queue_upcall); 1171da177e4SLinus Torvalds 1186070fe6fSTrond Myklebust static inline void 1196070fe6fSTrond Myklebust rpc_inode_setowner(struct inode *inode, void *private) 1206070fe6fSTrond Myklebust { 1216070fe6fSTrond Myklebust RPC_I(inode)->private = private; 1226070fe6fSTrond Myklebust } 1236070fe6fSTrond Myklebust 1241da177e4SLinus Torvalds static void 1251da177e4SLinus Torvalds rpc_close_pipes(struct inode *inode) 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 128b693ba4aSTrond Myklebust const struct rpc_pipe_ops *ops; 129e712804aS\"J. Bruce Fields\ int need_release; 1301da177e4SLinus Torvalds 1311b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 1329842ef35STrond Myklebust ops = rpci->ops; 1339842ef35STrond Myklebust if (ops != NULL) { 1349842ef35STrond Myklebust LIST_HEAD(free_list); 1359842ef35STrond Myklebust spin_lock(&inode->i_lock); 136e712804aS\"J. Bruce Fields\ need_release = rpci->nreaders != 0 || rpci->nwriters != 0; 1371da177e4SLinus Torvalds rpci->nreaders = 0; 1389842ef35STrond Myklebust list_splice_init(&rpci->in_upcall, &free_list); 1399842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 1409842ef35STrond Myklebust rpci->pipelen = 0; 1411da177e4SLinus Torvalds rpci->ops = NULL; 1429842ef35STrond Myklebust spin_unlock(&inode->i_lock); 1439842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); 1449842ef35STrond Myklebust rpci->nwriters = 0; 145e712804aS\"J. Bruce Fields\ if (need_release && ops->release_pipe) 1469842ef35STrond Myklebust ops->release_pipe(inode); 1474011cd97STrond Myklebust cancel_delayed_work_sync(&rpci->queue_timeout); 1481da177e4SLinus Torvalds } 1496070fe6fSTrond Myklebust rpc_inode_setowner(inode, NULL); 1501b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds static struct inode * 1541da177e4SLinus Torvalds rpc_alloc_inode(struct super_block *sb) 1551da177e4SLinus Torvalds { 1561da177e4SLinus Torvalds struct rpc_inode *rpci; 157e94b1766SChristoph Lameter rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); 1581da177e4SLinus Torvalds if (!rpci) 1591da177e4SLinus Torvalds return NULL; 1601da177e4SLinus Torvalds return &rpci->vfs_inode; 1611da177e4SLinus Torvalds } 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds static void 1641da177e4SLinus Torvalds rpc_destroy_inode(struct inode *inode) 1651da177e4SLinus Torvalds { 1661da177e4SLinus Torvalds kmem_cache_free(rpc_inode_cachep, RPC_I(inode)); 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds static int 1701da177e4SLinus Torvalds rpc_pipe_open(struct inode *inode, struct file *filp) 1711da177e4SLinus Torvalds { 1721da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 173c3810608S\"J. Bruce Fields\ int first_open; 1741da177e4SLinus Torvalds int res = -ENXIO; 1751da177e4SLinus Torvalds 1761b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 177c3810608S\"J. Bruce Fields\ if (rpci->ops == NULL) 178c3810608S\"J. Bruce Fields\ goto out; 179c3810608S\"J. Bruce Fields\ first_open = rpci->nreaders == 0 && rpci->nwriters == 0; 180c3810608S\"J. Bruce Fields\ if (first_open && rpci->ops->open_pipe) { 181c3810608S\"J. Bruce Fields\ res = rpci->ops->open_pipe(inode); 182c3810608S\"J. Bruce Fields\ if (res) 183c3810608S\"J. Bruce Fields\ goto out; 184c3810608S\"J. Bruce Fields\ } 1851da177e4SLinus Torvalds if (filp->f_mode & FMODE_READ) 1861da177e4SLinus Torvalds rpci->nreaders++; 1871da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 1881da177e4SLinus Torvalds rpci->nwriters++; 1891da177e4SLinus Torvalds res = 0; 190c3810608S\"J. Bruce Fields\ out: 1911b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 1921da177e4SLinus Torvalds return res; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds static int 1961da177e4SLinus Torvalds rpc_pipe_release(struct inode *inode, struct file *filp) 1971da177e4SLinus Torvalds { 198969b7f25STrond Myklebust struct rpc_inode *rpci = RPC_I(inode); 1991da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 200e712804aS\"J. Bruce Fields\ int last_close; 2011da177e4SLinus Torvalds 2021b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2031da177e4SLinus Torvalds if (rpci->ops == NULL) 2041da177e4SLinus Torvalds goto out; 2051da177e4SLinus Torvalds msg = (struct rpc_pipe_msg *)filp->private_data; 2061da177e4SLinus Torvalds if (msg != NULL) { 2079842ef35STrond Myklebust spin_lock(&inode->i_lock); 20848e49187STrond Myklebust msg->errno = -EAGAIN; 2099842ef35STrond Myklebust list_del(&msg->list); 2109842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2111da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 2141da177e4SLinus Torvalds rpci->nwriters --; 2159842ef35STrond Myklebust if (filp->f_mode & FMODE_READ) { 2161da177e4SLinus Torvalds rpci->nreaders --; 2179842ef35STrond Myklebust if (rpci->nreaders == 0) { 2189842ef35STrond Myklebust LIST_HEAD(free_list); 2199842ef35STrond Myklebust spin_lock(&inode->i_lock); 2209842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 2219842ef35STrond Myklebust rpci->pipelen = 0; 2229842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2239842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, 2249842ef35STrond Myklebust rpci->ops->destroy_msg, -EAGAIN); 2259842ef35STrond Myklebust } 2269842ef35STrond Myklebust } 227e712804aS\"J. Bruce Fields\ last_close = rpci->nwriters == 0 && rpci->nreaders == 0; 228e712804aS\"J. Bruce Fields\ if (last_close && rpci->ops->release_pipe) 2291da177e4SLinus Torvalds rpci->ops->release_pipe(inode); 2301da177e4SLinus Torvalds out: 2311b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2321da177e4SLinus Torvalds return 0; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds static ssize_t 2361da177e4SLinus Torvalds rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) 2371da177e4SLinus Torvalds { 238303b46bbSJosef Sipek struct inode *inode = filp->f_path.dentry->d_inode; 2391da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 2401da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 2411da177e4SLinus Torvalds int res = 0; 2421da177e4SLinus Torvalds 2431b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2441da177e4SLinus Torvalds if (rpci->ops == NULL) { 2451da177e4SLinus Torvalds res = -EPIPE; 2461da177e4SLinus Torvalds goto out_unlock; 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds msg = filp->private_data; 2491da177e4SLinus Torvalds if (msg == NULL) { 2509842ef35STrond Myklebust spin_lock(&inode->i_lock); 2511da177e4SLinus Torvalds if (!list_empty(&rpci->pipe)) { 2521da177e4SLinus Torvalds msg = list_entry(rpci->pipe.next, 2531da177e4SLinus Torvalds struct rpc_pipe_msg, 2541da177e4SLinus Torvalds list); 2551da177e4SLinus Torvalds list_move(&msg->list, &rpci->in_upcall); 2561da177e4SLinus Torvalds rpci->pipelen -= msg->len; 2571da177e4SLinus Torvalds filp->private_data = msg; 2581da177e4SLinus Torvalds msg->copied = 0; 2591da177e4SLinus Torvalds } 2609842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2611da177e4SLinus Torvalds if (msg == NULL) 2621da177e4SLinus Torvalds goto out_unlock; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds /* NOTE: it is up to the callback to update msg->copied */ 2651da177e4SLinus Torvalds res = rpci->ops->upcall(filp, msg, buf, len); 2661da177e4SLinus Torvalds if (res < 0 || msg->len == msg->copied) { 2671da177e4SLinus Torvalds filp->private_data = NULL; 2689842ef35STrond Myklebust spin_lock(&inode->i_lock); 2699842ef35STrond Myklebust list_del(&msg->list); 2709842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2711da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds out_unlock: 2741b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2751da177e4SLinus Torvalds return res; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds static ssize_t 2791da177e4SLinus Torvalds rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) 2801da177e4SLinus Torvalds { 281303b46bbSJosef Sipek struct inode *inode = filp->f_path.dentry->d_inode; 2821da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 2831da177e4SLinus Torvalds int res; 2841da177e4SLinus Torvalds 2851b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2861da177e4SLinus Torvalds res = -EPIPE; 2871da177e4SLinus Torvalds if (rpci->ops != NULL) 2881da177e4SLinus Torvalds res = rpci->ops->downcall(filp, buf, len); 2891b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2901da177e4SLinus Torvalds return res; 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds static unsigned int 2941da177e4SLinus Torvalds rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) 2951da177e4SLinus Torvalds { 2961da177e4SLinus Torvalds struct rpc_inode *rpci; 2971da177e4SLinus Torvalds unsigned int mask = 0; 2981da177e4SLinus Torvalds 299303b46bbSJosef Sipek rpci = RPC_I(filp->f_path.dentry->d_inode); 3001da177e4SLinus Torvalds poll_wait(filp, &rpci->waitq, wait); 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds mask = POLLOUT | POLLWRNORM; 3031da177e4SLinus Torvalds if (rpci->ops == NULL) 3041da177e4SLinus Torvalds mask |= POLLERR | POLLHUP; 305eda4f9b7SJ. Bruce Fields if (filp->private_data || !list_empty(&rpci->pipe)) 3061da177e4SLinus Torvalds mask |= POLLIN | POLLRDNORM; 3071da177e4SLinus Torvalds return mask; 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds static int 3111da177e4SLinus Torvalds rpc_pipe_ioctl(struct inode *ino, struct file *filp, 3121da177e4SLinus Torvalds unsigned int cmd, unsigned long arg) 3131da177e4SLinus Torvalds { 314303b46bbSJosef Sipek struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); 3151da177e4SLinus Torvalds int len; 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds switch (cmd) { 3181da177e4SLinus Torvalds case FIONREAD: 3191da177e4SLinus Torvalds if (rpci->ops == NULL) 3201da177e4SLinus Torvalds return -EPIPE; 3211da177e4SLinus Torvalds len = rpci->pipelen; 3221da177e4SLinus Torvalds if (filp->private_data) { 3231da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 3241da177e4SLinus Torvalds msg = (struct rpc_pipe_msg *)filp->private_data; 3251da177e4SLinus Torvalds len += msg->len - msg->copied; 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds return put_user(len, (int __user *)arg); 3281da177e4SLinus Torvalds default: 3291da177e4SLinus Torvalds return -EINVAL; 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds 333da7071d7SArjan van de Ven static const struct file_operations rpc_pipe_fops = { 3341da177e4SLinus Torvalds .owner = THIS_MODULE, 3351da177e4SLinus Torvalds .llseek = no_llseek, 3361da177e4SLinus Torvalds .read = rpc_pipe_read, 3371da177e4SLinus Torvalds .write = rpc_pipe_write, 3381da177e4SLinus Torvalds .poll = rpc_pipe_poll, 3391da177e4SLinus Torvalds .ioctl = rpc_pipe_ioctl, 3401da177e4SLinus Torvalds .open = rpc_pipe_open, 3411da177e4SLinus Torvalds .release = rpc_pipe_release, 3421da177e4SLinus Torvalds }; 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds static int 3451da177e4SLinus Torvalds rpc_show_info(struct seq_file *m, void *v) 3461da177e4SLinus Torvalds { 3471da177e4SLinus Torvalds struct rpc_clnt *clnt = m->private; 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds seq_printf(m, "RPC server: %s\n", clnt->cl_server); 3501da177e4SLinus Torvalds seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, 3511da177e4SLinus Torvalds clnt->cl_prog, clnt->cl_vers); 352e7f78657SChuck Lever seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); 353e7f78657SChuck Lever seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); 354bf19aaceSJ. Bruce Fields seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); 3551da177e4SLinus Torvalds return 0; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds static int 3591da177e4SLinus Torvalds rpc_info_open(struct inode *inode, struct file *file) 3601da177e4SLinus Torvalds { 3611da177e4SLinus Torvalds struct rpc_clnt *clnt; 3621da177e4SLinus Torvalds int ret = single_open(file, rpc_show_info, NULL); 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds if (!ret) { 3651da177e4SLinus Torvalds struct seq_file *m = file->private_data; 3661b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 3671da177e4SLinus Torvalds clnt = RPC_I(inode)->private; 3681da177e4SLinus Torvalds if (clnt) { 36934f52e35STrond Myklebust kref_get(&clnt->cl_kref); 3701da177e4SLinus Torvalds m->private = clnt; 3711da177e4SLinus Torvalds } else { 3721da177e4SLinus Torvalds single_release(inode, file); 3731da177e4SLinus Torvalds ret = -EINVAL; 3741da177e4SLinus Torvalds } 3751b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds return ret; 3781da177e4SLinus Torvalds } 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds static int 3811da177e4SLinus Torvalds rpc_info_release(struct inode *inode, struct file *file) 3821da177e4SLinus Torvalds { 3831da177e4SLinus Torvalds struct seq_file *m = file->private_data; 3841da177e4SLinus Torvalds struct rpc_clnt *clnt = (struct rpc_clnt *)m->private; 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds if (clnt) 3871da177e4SLinus Torvalds rpc_release_client(clnt); 3881da177e4SLinus Torvalds return single_release(inode, file); 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds 391da7071d7SArjan van de Ven static const struct file_operations rpc_info_operations = { 3921da177e4SLinus Torvalds .owner = THIS_MODULE, 3931da177e4SLinus Torvalds .open = rpc_info_open, 3941da177e4SLinus Torvalds .read = seq_read, 3951da177e4SLinus Torvalds .llseek = seq_lseek, 3961da177e4SLinus Torvalds .release = rpc_info_release, 3971da177e4SLinus Torvalds }; 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds /* 4011da177e4SLinus Torvalds * We have a single directory with 1 node in it. 4021da177e4SLinus Torvalds */ 4031da177e4SLinus Torvalds enum { 4041da177e4SLinus Torvalds RPCAUTH_Root = 1, 4051da177e4SLinus Torvalds RPCAUTH_lockd, 4061da177e4SLinus Torvalds RPCAUTH_mount, 4071da177e4SLinus Torvalds RPCAUTH_nfs, 4081da177e4SLinus Torvalds RPCAUTH_portmap, 4091da177e4SLinus Torvalds RPCAUTH_statd, 41061054b14SOlga Kornievskaia RPCAUTH_nfsd4_cb, 4111da177e4SLinus Torvalds RPCAUTH_RootEOF 4121da177e4SLinus Torvalds }; 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds /* 4151da177e4SLinus Torvalds * Description of fs contents. 4161da177e4SLinus Torvalds */ 4171da177e4SLinus Torvalds struct rpc_filelist { 4181da177e4SLinus Torvalds char *name; 41999ac48f5SArjan van de Ven const struct file_operations *i_fop; 4207364af6aSTrond Myklebust umode_t mode; 4211da177e4SLinus Torvalds }; 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds static struct rpc_filelist files[] = { 4241da177e4SLinus Torvalds [RPCAUTH_lockd] = { 4251da177e4SLinus Torvalds .name = "lockd", 4261da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 4271da177e4SLinus Torvalds }, 4281da177e4SLinus Torvalds [RPCAUTH_mount] = { 4291da177e4SLinus Torvalds .name = "mount", 4301da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 4311da177e4SLinus Torvalds }, 4321da177e4SLinus Torvalds [RPCAUTH_nfs] = { 4331da177e4SLinus Torvalds .name = "nfs", 4341da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 4351da177e4SLinus Torvalds }, 4361da177e4SLinus Torvalds [RPCAUTH_portmap] = { 4371da177e4SLinus Torvalds .name = "portmap", 4381da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 4391da177e4SLinus Torvalds }, 4401da177e4SLinus Torvalds [RPCAUTH_statd] = { 4411da177e4SLinus Torvalds .name = "statd", 4421da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 4431da177e4SLinus Torvalds }, 44461054b14SOlga Kornievskaia [RPCAUTH_nfsd4_cb] = { 44561054b14SOlga Kornievskaia .name = "nfsd4_cb", 44661054b14SOlga Kornievskaia .mode = S_IFDIR | S_IRUGO | S_IXUGO, 44761054b14SOlga Kornievskaia }, 4481da177e4SLinus Torvalds }; 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds enum { 4511da177e4SLinus Torvalds RPCAUTH_info = 2, 4521da177e4SLinus Torvalds RPCAUTH_EOF 4531da177e4SLinus Torvalds }; 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds static struct rpc_filelist authfiles[] = { 4561da177e4SLinus Torvalds [RPCAUTH_info] = { 4571da177e4SLinus Torvalds .name = "info", 4581da177e4SLinus Torvalds .i_fop = &rpc_info_operations, 4591da177e4SLinus Torvalds .mode = S_IFREG | S_IRUSR, 4601da177e4SLinus Torvalds }, 4611da177e4SLinus Torvalds }; 4621da177e4SLinus Torvalds 46354281548STrond Myklebust struct vfsmount *rpc_get_mount(void) 4641da177e4SLinus Torvalds { 46554281548STrond Myklebust int err; 46654281548STrond Myklebust 4671f5ce9e9STrond Myklebust err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mount, &rpc_mount_count); 46854281548STrond Myklebust if (err != 0) 46954281548STrond Myklebust return ERR_PTR(err); 47054281548STrond Myklebust return rpc_mount; 4711da177e4SLinus Torvalds } 4721da177e4SLinus Torvalds 47354281548STrond Myklebust void rpc_put_mount(void) 4741da177e4SLinus Torvalds { 4751da177e4SLinus Torvalds simple_release_fs(&rpc_mount, &rpc_mount_count); 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds 47862e1761cSTrond Myklebust static int rpc_delete_dentry(struct dentry *dentry) 47962e1761cSTrond Myklebust { 48062e1761cSTrond Myklebust return 1; 48162e1761cSTrond Myklebust } 48262e1761cSTrond Myklebust 4833ba13d17SAl Viro static const struct dentry_operations rpc_dentry_operations = { 48462e1761cSTrond Myklebust .d_delete = rpc_delete_dentry, 48562e1761cSTrond Myklebust }; 48662e1761cSTrond Myklebust 487b5bb61daSTrond Myklebust static int __rpc_lookup_path(const char *pathname, unsigned flags, 488b5bb61daSTrond Myklebust struct nameidata *nd) 489f134585aSTrond Myklebust { 4904ac4efc1SJosef 'Jeff' Sipek struct vfsmount *mnt; 4914ac4efc1SJosef 'Jeff' Sipek 492b5bb61daSTrond Myklebust if (pathname[0] == '\0') 493f134585aSTrond Myklebust return -ENOENT; 4944ac4efc1SJosef 'Jeff' Sipek 4954ac4efc1SJosef 'Jeff' Sipek mnt = rpc_get_mount(); 4964ac4efc1SJosef 'Jeff' Sipek if (IS_ERR(mnt)) { 497f134585aSTrond Myklebust printk(KERN_WARNING "%s: %s failed to mount " 4980dc47877SHarvey Harrison "pseudofilesystem \n", __FILE__, __func__); 4994ac4efc1SJosef 'Jeff' Sipek return PTR_ERR(mnt); 500f134585aSTrond Myklebust } 501f134585aSTrond Myklebust 502b5bb61daSTrond Myklebust if (vfs_path_lookup(mnt->mnt_root, mnt, pathname, flags, nd)) { 503f134585aSTrond Myklebust printk(KERN_WARNING "%s: %s failed to find path %s\n", 504b5bb61daSTrond Myklebust __FILE__, __func__, pathname); 505f134585aSTrond Myklebust rpc_put_mount(); 506f134585aSTrond Myklebust return -ENOENT; 507f134585aSTrond Myklebust } 508f134585aSTrond Myklebust return 0; 509f134585aSTrond Myklebust } 510f134585aSTrond Myklebust 511b5bb61daSTrond Myklebust static int rpc_lookup_parent(const char *pathname, struct nameidata *nd) 512b5bb61daSTrond Myklebust { 513b5bb61daSTrond Myklebust return __rpc_lookup_path(pathname, LOOKUP_PARENT, nd); 514b5bb61daSTrond Myklebust } 515b5bb61daSTrond Myklebust 516f134585aSTrond Myklebust static void 517f134585aSTrond Myklebust rpc_release_path(struct nameidata *nd) 518f134585aSTrond Myklebust { 5191d957f9bSJan Blunck path_put(&nd->path); 520f134585aSTrond Myklebust rpc_put_mount(); 521f134585aSTrond Myklebust } 522f134585aSTrond Myklebust 5231da177e4SLinus Torvalds static struct inode * 5247364af6aSTrond Myklebust rpc_get_inode(struct super_block *sb, umode_t mode) 5251da177e4SLinus Torvalds { 5261da177e4SLinus Torvalds struct inode *inode = new_inode(sb); 5271da177e4SLinus Torvalds if (!inode) 5281da177e4SLinus Torvalds return NULL; 5291da177e4SLinus Torvalds inode->i_mode = mode; 5301da177e4SLinus Torvalds inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 5311da177e4SLinus Torvalds switch(mode & S_IFMT) { 5321da177e4SLinus Torvalds case S_IFDIR: 5331da177e4SLinus Torvalds inode->i_fop = &simple_dir_operations; 5341da177e4SLinus Torvalds inode->i_op = &simple_dir_inode_operations; 535d8c76e6fSDave Hansen inc_nlink(inode); 5361da177e4SLinus Torvalds default: 5371da177e4SLinus Torvalds break; 5381da177e4SLinus Torvalds } 5391da177e4SLinus Torvalds return inode; 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds 5427589806eSTrond Myklebust static int __rpc_create_common(struct inode *dir, struct dentry *dentry, 5437589806eSTrond Myklebust umode_t mode, 5447589806eSTrond Myklebust const struct file_operations *i_fop, 5457589806eSTrond Myklebust void *private) 5467589806eSTrond Myklebust { 5477589806eSTrond Myklebust struct inode *inode; 5487589806eSTrond Myklebust 5497589806eSTrond Myklebust BUG_ON(!d_unhashed(dentry)); 5507589806eSTrond Myklebust inode = rpc_get_inode(dir->i_sb, mode); 5517589806eSTrond Myklebust if (!inode) 5527589806eSTrond Myklebust goto out_err; 5537589806eSTrond Myklebust inode->i_ino = iunique(dir->i_sb, 100); 5547589806eSTrond Myklebust if (i_fop) 5557589806eSTrond Myklebust inode->i_fop = i_fop; 5567589806eSTrond Myklebust if (private) 5577589806eSTrond Myklebust rpc_inode_setowner(inode, private); 5587589806eSTrond Myklebust d_add(dentry, inode); 5597589806eSTrond Myklebust return 0; 5607589806eSTrond Myklebust out_err: 5617589806eSTrond Myklebust printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", 5627589806eSTrond Myklebust __FILE__, __func__, dentry->d_name.name); 5637589806eSTrond Myklebust dput(dentry); 5647589806eSTrond Myklebust return -ENOMEM; 5657589806eSTrond Myklebust } 5667589806eSTrond Myklebust 5677589806eSTrond Myklebust static int __rpc_mkdir(struct inode *dir, struct dentry *dentry, 5687589806eSTrond Myklebust umode_t mode, 5697589806eSTrond Myklebust const struct file_operations *i_fop, 5707589806eSTrond Myklebust void *private) 5717589806eSTrond Myklebust { 5727589806eSTrond Myklebust int err; 5737589806eSTrond Myklebust 5747589806eSTrond Myklebust err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private); 5757589806eSTrond Myklebust if (err) 5767589806eSTrond Myklebust return err; 5777589806eSTrond Myklebust inc_nlink(dir); 5787589806eSTrond Myklebust fsnotify_mkdir(dir, dentry); 5797589806eSTrond Myklebust return 0; 5807589806eSTrond Myklebust } 5817589806eSTrond Myklebust 5827589806eSTrond Myklebust static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, 5837589806eSTrond Myklebust umode_t mode, 5847589806eSTrond Myklebust const struct file_operations *i_fop, 5857589806eSTrond Myklebust void *private, 5867589806eSTrond Myklebust const struct rpc_pipe_ops *ops, 5877589806eSTrond Myklebust int flags) 5887589806eSTrond Myklebust { 5897589806eSTrond Myklebust struct rpc_inode *rpci; 5907589806eSTrond Myklebust int err; 5917589806eSTrond Myklebust 5927589806eSTrond Myklebust err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private); 5937589806eSTrond Myklebust if (err) 5947589806eSTrond Myklebust return err; 5957589806eSTrond Myklebust rpci = RPC_I(dentry->d_inode); 5967589806eSTrond Myklebust rpci->nkern_readwriters = 1; 5977589806eSTrond Myklebust rpci->private = private; 5987589806eSTrond Myklebust rpci->flags = flags; 5997589806eSTrond Myklebust rpci->ops = ops; 6007589806eSTrond Myklebust fsnotify_create(dir, dentry); 6017589806eSTrond Myklebust return 0; 6027589806eSTrond Myklebust } 6037589806eSTrond Myklebust 6041da177e4SLinus Torvalds /* 6051da177e4SLinus Torvalds * FIXME: This probably has races. 6061da177e4SLinus Torvalds */ 6079b45b74cSChuck Lever static void rpc_depopulate(struct dentry *parent, 6089b45b74cSChuck Lever unsigned long start, unsigned long eof) 6091da177e4SLinus Torvalds { 6101da177e4SLinus Torvalds struct inode *dir = parent->d_inode; 6111da177e4SLinus Torvalds struct list_head *pos, *next; 6121da177e4SLinus Torvalds struct dentry *dentry, *dvec[10]; 6131da177e4SLinus Torvalds int n = 0; 6141da177e4SLinus Torvalds 615c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD); 6161da177e4SLinus Torvalds repeat: 6171da177e4SLinus Torvalds spin_lock(&dcache_lock); 6181da177e4SLinus Torvalds list_for_each_safe(pos, next, &parent->d_subdirs) { 6195160ee6fSEric Dumazet dentry = list_entry(pos, struct dentry, d_u.d_child); 62062e1761cSTrond Myklebust if (!dentry->d_inode || 62162e1761cSTrond Myklebust dentry->d_inode->i_ino < start || 62262e1761cSTrond Myklebust dentry->d_inode->i_ino >= eof) 62362e1761cSTrond Myklebust continue; 6241da177e4SLinus Torvalds spin_lock(&dentry->d_lock); 6251da177e4SLinus Torvalds if (!d_unhashed(dentry)) { 6261da177e4SLinus Torvalds dget_locked(dentry); 6271da177e4SLinus Torvalds __d_drop(dentry); 6281da177e4SLinus Torvalds spin_unlock(&dentry->d_lock); 6291da177e4SLinus Torvalds dvec[n++] = dentry; 6301da177e4SLinus Torvalds if (n == ARRAY_SIZE(dvec)) 6311da177e4SLinus Torvalds break; 6321da177e4SLinus Torvalds } else 6331da177e4SLinus Torvalds spin_unlock(&dentry->d_lock); 6341da177e4SLinus Torvalds } 6351da177e4SLinus Torvalds spin_unlock(&dcache_lock); 6361da177e4SLinus Torvalds if (n) { 6371da177e4SLinus Torvalds do { 6381da177e4SLinus Torvalds dentry = dvec[--n]; 63962e1761cSTrond Myklebust if (S_ISREG(dentry->d_inode->i_mode)) 6401da177e4SLinus Torvalds simple_unlink(dir, dentry); 64162e1761cSTrond Myklebust else if (S_ISDIR(dentry->d_inode->i_mode)) 64262e1761cSTrond Myklebust simple_rmdir(dir, dentry); 64362e1761cSTrond Myklebust d_delete(dentry); 6441da177e4SLinus Torvalds dput(dentry); 6451da177e4SLinus Torvalds } while (n); 6461da177e4SLinus Torvalds goto repeat; 6471da177e4SLinus Torvalds } 6481b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds static int 6521da177e4SLinus Torvalds rpc_populate(struct dentry *parent, 6531da177e4SLinus Torvalds struct rpc_filelist *files, 6541da177e4SLinus Torvalds int start, int eof) 6551da177e4SLinus Torvalds { 6561da177e4SLinus Torvalds struct inode *inode, *dir = parent->d_inode; 6571da177e4SLinus Torvalds void *private = RPC_I(dir)->private; 6581da177e4SLinus Torvalds struct dentry *dentry; 6597364af6aSTrond Myklebust umode_t mode; 6607364af6aSTrond Myklebust int i; 6611da177e4SLinus Torvalds 6621b1dcc1bSJes Sorensen mutex_lock(&dir->i_mutex); 6631da177e4SLinus Torvalds for (i = start; i < eof; i++) { 6641da177e4SLinus Torvalds dentry = d_alloc_name(parent, files[i].name); 6651da177e4SLinus Torvalds if (!dentry) 6661da177e4SLinus Torvalds goto out_bad; 66762e1761cSTrond Myklebust dentry->d_op = &rpc_dentry_operations; 6681da177e4SLinus Torvalds mode = files[i].mode; 6691da177e4SLinus Torvalds inode = rpc_get_inode(dir->i_sb, mode); 6701da177e4SLinus Torvalds if (!inode) { 6711da177e4SLinus Torvalds dput(dentry); 6721da177e4SLinus Torvalds goto out_bad; 6731da177e4SLinus Torvalds } 6741da177e4SLinus Torvalds inode->i_ino = i; 6751da177e4SLinus Torvalds if (files[i].i_fop) 6761da177e4SLinus Torvalds inode->i_fop = files[i].i_fop; 6771da177e4SLinus Torvalds if (private) 6781da177e4SLinus Torvalds rpc_inode_setowner(inode, private); 6791da177e4SLinus Torvalds if (S_ISDIR(mode)) 680d8c76e6fSDave Hansen inc_nlink(dir); 6811da177e4SLinus Torvalds d_add(dentry, inode); 68250e437d5STrond Myklebust fsnotify_create(dir, dentry); 6831da177e4SLinus Torvalds } 6841b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 6851da177e4SLinus Torvalds return 0; 6861da177e4SLinus Torvalds out_bad: 6871b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 6881da177e4SLinus Torvalds printk(KERN_WARNING "%s: %s failed to populate directory %s\n", 6890dc47877SHarvey Harrison __FILE__, __func__, parent->d_name.name); 6901da177e4SLinus Torvalds return -ENOMEM; 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds 693f134585aSTrond Myklebust static int 694f134585aSTrond Myklebust __rpc_rmdir(struct inode *dir, struct dentry *dentry) 695278c995cSChristoph Hellwig { 696f134585aSTrond Myklebust int error; 69762e1761cSTrond Myklebust error = simple_rmdir(dir, dentry); 69862e1761cSTrond Myklebust if (!error) 69962e1761cSTrond Myklebust d_delete(dentry); 700f134585aSTrond Myklebust return error; 701f134585aSTrond Myklebust } 702f134585aSTrond Myklebust 703f134585aSTrond Myklebust static struct dentry * 70434f30896STrond Myklebust rpc_lookup_create(struct dentry *parent, const char *name, int len, int exclusive) 705f134585aSTrond Myklebust { 706158998b6STrond Myklebust struct inode *dir = parent->d_inode; 707f134585aSTrond Myklebust struct dentry *dentry; 708f134585aSTrond Myklebust 709c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 710158998b6STrond Myklebust dentry = lookup_one_len(name, parent, len); 711f134585aSTrond Myklebust if (IS_ERR(dentry)) 712f134585aSTrond Myklebust goto out_err; 71362e1761cSTrond Myklebust if (!dentry->d_inode) 71462e1761cSTrond Myklebust dentry->d_op = &rpc_dentry_operations; 71562e1761cSTrond Myklebust else if (exclusive) { 716f134585aSTrond Myklebust dput(dentry); 717f134585aSTrond Myklebust dentry = ERR_PTR(-EEXIST); 718f134585aSTrond Myklebust goto out_err; 719f134585aSTrond Myklebust } 720f134585aSTrond Myklebust return dentry; 721f134585aSTrond Myklebust out_err: 7221b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 723158998b6STrond Myklebust return dentry; 724158998b6STrond Myklebust } 725158998b6STrond Myklebust 726158998b6STrond Myklebust static struct dentry * 727158998b6STrond Myklebust rpc_lookup_negative(char *path, struct nameidata *nd) 728158998b6STrond Myklebust { 729158998b6STrond Myklebust struct dentry *dentry; 730158998b6STrond Myklebust int error; 731158998b6STrond Myklebust 732158998b6STrond Myklebust if ((error = rpc_lookup_parent(path, nd)) != 0) 733158998b6STrond Myklebust return ERR_PTR(error); 7344ac91378SJan Blunck dentry = rpc_lookup_create(nd->path.dentry, nd->last.name, nd->last.len, 7354ac91378SJan Blunck 1); 736158998b6STrond Myklebust if (IS_ERR(dentry)) 737f134585aSTrond Myklebust rpc_release_path(nd); 738f134585aSTrond Myklebust return dentry; 739f134585aSTrond Myklebust } 740f134585aSTrond Myklebust 74193a44a75SJ. Bruce Fields /** 74293a44a75SJ. Bruce Fields * rpc_mkdir - Create a new directory in rpc_pipefs 74393a44a75SJ. Bruce Fields * @path: path from the rpc_pipefs root to the new directory 74465b6e42cSRandy Dunlap * @rpc_client: rpc client to associate with this directory 74593a44a75SJ. Bruce Fields * 74693a44a75SJ. Bruce Fields * This creates a directory at the given @path associated with 74793a44a75SJ. Bruce Fields * @rpc_clnt, which will contain a file named "info" with some basic 74893a44a75SJ. Bruce Fields * information about the client, together with any "pipes" that may 74993a44a75SJ. Bruce Fields * later be created using rpc_mkpipe(). 75093a44a75SJ. Bruce Fields */ 751f134585aSTrond Myklebust struct dentry * 752f134585aSTrond Myklebust rpc_mkdir(char *path, struct rpc_clnt *rpc_client) 753f134585aSTrond Myklebust { 754f134585aSTrond Myklebust struct nameidata nd; 755f134585aSTrond Myklebust struct dentry *dentry; 756f134585aSTrond Myklebust struct inode *dir; 757f134585aSTrond Myklebust int error; 758f134585aSTrond Myklebust 759f134585aSTrond Myklebust dentry = rpc_lookup_negative(path, &nd); 760f134585aSTrond Myklebust if (IS_ERR(dentry)) 761f134585aSTrond Myklebust return dentry; 7624ac91378SJan Blunck dir = nd.path.dentry->d_inode; 7637589806eSTrond Myklebust error = __rpc_mkdir(dir, dentry, S_IRUGO | S_IXUGO, NULL, rpc_client); 7647589806eSTrond Myklebust if (error != 0) 7657589806eSTrond Myklebust goto out_err; 766f134585aSTrond Myklebust error = rpc_populate(dentry, authfiles, 767f134585aSTrond Myklebust RPCAUTH_info, RPCAUTH_EOF); 768f134585aSTrond Myklebust if (error) 769f134585aSTrond Myklebust goto err_depopulate; 7705c3e985aSTrond Myklebust dget(dentry); 771f134585aSTrond Myklebust out: 7721b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 773f134585aSTrond Myklebust rpc_release_path(&nd); 7745c3e985aSTrond Myklebust return dentry; 775f134585aSTrond Myklebust err_depopulate: 77662e1761cSTrond Myklebust rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); 777f134585aSTrond Myklebust __rpc_rmdir(dir, dentry); 7787589806eSTrond Myklebust out_err: 779f134585aSTrond Myklebust printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", 7800dc47877SHarvey Harrison __FILE__, __func__, path, error); 781f134585aSTrond Myklebust dentry = ERR_PTR(error); 782f134585aSTrond Myklebust goto out; 783f134585aSTrond Myklebust } 784f134585aSTrond Myklebust 78593a44a75SJ. Bruce Fields /** 78693a44a75SJ. Bruce Fields * rpc_rmdir - Remove a directory created with rpc_mkdir() 78793a44a75SJ. Bruce Fields * @dentry: directory to remove 78893a44a75SJ. Bruce Fields */ 789f134585aSTrond Myklebust int 790dff02cc1STrond Myklebust rpc_rmdir(struct dentry *dentry) 791f134585aSTrond Myklebust { 792dff02cc1STrond Myklebust struct dentry *parent; 793f134585aSTrond Myklebust struct inode *dir; 794f134585aSTrond Myklebust int error; 795f134585aSTrond Myklebust 796dff02cc1STrond Myklebust parent = dget_parent(dentry); 797dff02cc1STrond Myklebust dir = parent->d_inode; 798c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 79962e1761cSTrond Myklebust rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); 800f134585aSTrond Myklebust error = __rpc_rmdir(dir, dentry); 801f134585aSTrond Myklebust dput(dentry); 8021b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 803dff02cc1STrond Myklebust dput(parent); 804f134585aSTrond Myklebust return error; 805f134585aSTrond Myklebust } 8061da177e4SLinus Torvalds 80793a44a75SJ. Bruce Fields /** 80893a44a75SJ. Bruce Fields * rpc_mkpipe - make an rpc_pipefs file for kernel<->userspace communication 80993a44a75SJ. Bruce Fields * @parent: dentry of directory to create new "pipe" in 81093a44a75SJ. Bruce Fields * @name: name of pipe 81193a44a75SJ. Bruce Fields * @private: private data to associate with the pipe, for the caller's use 81293a44a75SJ. Bruce Fields * @ops: operations defining the behavior of the pipe: upcall, downcall, 813c3810608S\"J. Bruce Fields\ * release_pipe, open_pipe, and destroy_msg. 81465b6e42cSRandy Dunlap * @flags: rpc_inode flags 81593a44a75SJ. Bruce Fields * 81693a44a75SJ. Bruce Fields * Data is made available for userspace to read by calls to 81793a44a75SJ. Bruce Fields * rpc_queue_upcall(). The actual reads will result in calls to 81893a44a75SJ. Bruce Fields * @ops->upcall, which will be called with the file pointer, 81993a44a75SJ. Bruce Fields * message, and userspace buffer to copy to. 82093a44a75SJ. Bruce Fields * 82193a44a75SJ. Bruce Fields * Writes can come at any time, and do not necessarily have to be 82293a44a75SJ. Bruce Fields * responses to upcalls. They will result in calls to @msg->downcall. 82393a44a75SJ. Bruce Fields * 82493a44a75SJ. Bruce Fields * The @private argument passed here will be available to all these methods 82593a44a75SJ. Bruce Fields * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. 82693a44a75SJ. Bruce Fields */ 827b693ba4aSTrond Myklebust struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, 828b693ba4aSTrond Myklebust void *private, const struct rpc_pipe_ops *ops, 829b693ba4aSTrond Myklebust int flags) 8301da177e4SLinus Torvalds { 8311da177e4SLinus Torvalds struct dentry *dentry; 8327589806eSTrond Myklebust struct inode *dir = parent->d_inode; 8337364af6aSTrond Myklebust umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR; 8347589806eSTrond Myklebust int err; 8357364af6aSTrond Myklebust 8367364af6aSTrond Myklebust if (ops->upcall == NULL) 8377364af6aSTrond Myklebust umode &= ~S_IRUGO; 8387364af6aSTrond Myklebust if (ops->downcall == NULL) 8397364af6aSTrond Myklebust umode &= ~S_IWUGO; 8401da177e4SLinus Torvalds 84134f30896STrond Myklebust dentry = rpc_lookup_create(parent, name, strlen(name), 0); 8421da177e4SLinus Torvalds if (IS_ERR(dentry)) 843f134585aSTrond Myklebust return dentry; 844158998b6STrond Myklebust dir = parent->d_inode; 84534f30896STrond Myklebust if (dentry->d_inode) { 8467589806eSTrond Myklebust struct rpc_inode *rpci = RPC_I(dentry->d_inode); 84734f30896STrond Myklebust if (rpci->private != private || 84834f30896STrond Myklebust rpci->ops != ops || 84934f30896STrond Myklebust rpci->flags != flags) { 85034f30896STrond Myklebust dput (dentry); 85134f30896STrond Myklebust dentry = ERR_PTR(-EBUSY); 85234f30896STrond Myklebust } 85303a1256fSTrond Myklebust rpci->nkern_readwriters++; 85434f30896STrond Myklebust goto out; 85534f30896STrond Myklebust } 8567589806eSTrond Myklebust 8577589806eSTrond Myklebust err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops, 8587589806eSTrond Myklebust private, ops, flags); 8597589806eSTrond Myklebust if (err) 8607589806eSTrond Myklebust goto out_err; 8615c3e985aSTrond Myklebust dget(dentry); 862f134585aSTrond Myklebust out: 8631b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 8645c3e985aSTrond Myklebust return dentry; 8657589806eSTrond Myklebust out_err: 8667589806eSTrond Myklebust dentry = ERR_PTR(err); 867158998b6STrond Myklebust printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", 8680dc47877SHarvey Harrison __FILE__, __func__, parent->d_name.name, name, 8697589806eSTrond Myklebust err); 870f134585aSTrond Myklebust goto out; 8711da177e4SLinus Torvalds } 872468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_mkpipe); 8731da177e4SLinus Torvalds 87493a44a75SJ. Bruce Fields /** 87593a44a75SJ. Bruce Fields * rpc_unlink - remove a pipe 87693a44a75SJ. Bruce Fields * @dentry: dentry for the pipe, as returned from rpc_mkpipe 87793a44a75SJ. Bruce Fields * 87893a44a75SJ. Bruce Fields * After this call, lookups will no longer find the pipe, and any 87993a44a75SJ. Bruce Fields * attempts to read or write using preexisting opens of the pipe will 88093a44a75SJ. Bruce Fields * return -EPIPE. 88193a44a75SJ. Bruce Fields */ 882f134585aSTrond Myklebust int 8835d67476fSTrond Myklebust rpc_unlink(struct dentry *dentry) 8841da177e4SLinus Torvalds { 8855d67476fSTrond Myklebust struct dentry *parent; 886f134585aSTrond Myklebust struct inode *dir; 8875d67476fSTrond Myklebust int error = 0; 8881da177e4SLinus Torvalds 8895d67476fSTrond Myklebust parent = dget_parent(dentry); 8905d67476fSTrond Myklebust dir = parent->d_inode; 891c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 89203a1256fSTrond Myklebust if (--RPC_I(dentry->d_inode)->nkern_readwriters == 0) { 8931da177e4SLinus Torvalds rpc_close_pipes(dentry->d_inode); 894f134585aSTrond Myklebust error = simple_unlink(dir, dentry); 89562e1761cSTrond Myklebust if (!error) 89662e1761cSTrond Myklebust d_delete(dentry); 89703a1256fSTrond Myklebust } 89868adb0afSTrond Myklebust dput(dentry); 8991b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 9005d67476fSTrond Myklebust dput(parent); 901f134585aSTrond Myklebust return error; 9021da177e4SLinus Torvalds } 903468039eeSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_unlink); 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds /* 9061da177e4SLinus Torvalds * populate the filesystem 9071da177e4SLinus Torvalds */ 9081da177e4SLinus Torvalds static struct super_operations s_ops = { 9091da177e4SLinus Torvalds .alloc_inode = rpc_alloc_inode, 9101da177e4SLinus Torvalds .destroy_inode = rpc_destroy_inode, 9111da177e4SLinus Torvalds .statfs = simple_statfs, 9121da177e4SLinus Torvalds }; 9131da177e4SLinus Torvalds 9141da177e4SLinus Torvalds #define RPCAUTH_GSSMAGIC 0x67596969 9151da177e4SLinus Torvalds 9161da177e4SLinus Torvalds static int 9171da177e4SLinus Torvalds rpc_fill_super(struct super_block *sb, void *data, int silent) 9181da177e4SLinus Torvalds { 9191da177e4SLinus Torvalds struct inode *inode; 9201da177e4SLinus Torvalds struct dentry *root; 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds sb->s_blocksize = PAGE_CACHE_SIZE; 9231da177e4SLinus Torvalds sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 9241da177e4SLinus Torvalds sb->s_magic = RPCAUTH_GSSMAGIC; 9251da177e4SLinus Torvalds sb->s_op = &s_ops; 9261da177e4SLinus Torvalds sb->s_time_gran = 1; 9271da177e4SLinus Torvalds 9281da177e4SLinus Torvalds inode = rpc_get_inode(sb, S_IFDIR | 0755); 9291da177e4SLinus Torvalds if (!inode) 9301da177e4SLinus Torvalds return -ENOMEM; 9311da177e4SLinus Torvalds root = d_alloc_root(inode); 9321da177e4SLinus Torvalds if (!root) { 9331da177e4SLinus Torvalds iput(inode); 9341da177e4SLinus Torvalds return -ENOMEM; 9351da177e4SLinus Torvalds } 9361da177e4SLinus Torvalds if (rpc_populate(root, files, RPCAUTH_Root + 1, RPCAUTH_RootEOF)) 9371da177e4SLinus Torvalds goto out; 9381da177e4SLinus Torvalds sb->s_root = root; 9391da177e4SLinus Torvalds return 0; 9401da177e4SLinus Torvalds out: 9411da177e4SLinus Torvalds d_genocide(root); 9421da177e4SLinus Torvalds dput(root); 9431da177e4SLinus Torvalds return -ENOMEM; 9441da177e4SLinus Torvalds } 9451da177e4SLinus Torvalds 946454e2398SDavid Howells static int 9471da177e4SLinus Torvalds rpc_get_sb(struct file_system_type *fs_type, 948454e2398SDavid Howells int flags, const char *dev_name, void *data, struct vfsmount *mnt) 9491da177e4SLinus Torvalds { 950454e2398SDavid Howells return get_sb_single(fs_type, flags, data, rpc_fill_super, mnt); 9511da177e4SLinus Torvalds } 9521da177e4SLinus Torvalds 9531da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type = { 9541da177e4SLinus Torvalds .owner = THIS_MODULE, 9551da177e4SLinus Torvalds .name = "rpc_pipefs", 9561da177e4SLinus Torvalds .get_sb = rpc_get_sb, 9571da177e4SLinus Torvalds .kill_sb = kill_litter_super, 9581da177e4SLinus Torvalds }; 9591da177e4SLinus Torvalds 9601da177e4SLinus Torvalds static void 96151cc5068SAlexey Dobriyan init_once(void *foo) 9621da177e4SLinus Torvalds { 9631da177e4SLinus Torvalds struct rpc_inode *rpci = (struct rpc_inode *) foo; 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds inode_init_once(&rpci->vfs_inode); 9661da177e4SLinus Torvalds rpci->private = NULL; 9671da177e4SLinus Torvalds rpci->nreaders = 0; 9681da177e4SLinus Torvalds rpci->nwriters = 0; 9691da177e4SLinus Torvalds INIT_LIST_HEAD(&rpci->in_upcall); 9706e84c7b6STrond Myklebust INIT_LIST_HEAD(&rpci->in_downcall); 9711da177e4SLinus Torvalds INIT_LIST_HEAD(&rpci->pipe); 9721da177e4SLinus Torvalds rpci->pipelen = 0; 9731da177e4SLinus Torvalds init_waitqueue_head(&rpci->waitq); 97452bad64dSDavid Howells INIT_DELAYED_WORK(&rpci->queue_timeout, 97565f27f38SDavid Howells rpc_timeout_upcall_queue); 9761da177e4SLinus Torvalds rpci->ops = NULL; 9771da177e4SLinus Torvalds } 9781da177e4SLinus Torvalds 9791da177e4SLinus Torvalds int register_rpc_pipefs(void) 9801da177e4SLinus Torvalds { 9815bd5f581SAkinobu Mita int err; 9825bd5f581SAkinobu Mita 9831da177e4SLinus Torvalds rpc_inode_cachep = kmem_cache_create("rpc_inode_cache", 9841da177e4SLinus Torvalds sizeof(struct rpc_inode), 985fffb60f9SPaul Jackson 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| 986fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 98720c2df83SPaul Mundt init_once); 9881da177e4SLinus Torvalds if (!rpc_inode_cachep) 9891da177e4SLinus Torvalds return -ENOMEM; 9905bd5f581SAkinobu Mita err = register_filesystem(&rpc_pipe_fs_type); 9915bd5f581SAkinobu Mita if (err) { 9925bd5f581SAkinobu Mita kmem_cache_destroy(rpc_inode_cachep); 9935bd5f581SAkinobu Mita return err; 9945bd5f581SAkinobu Mita } 9955bd5f581SAkinobu Mita 9961da177e4SLinus Torvalds return 0; 9971da177e4SLinus Torvalds } 9981da177e4SLinus Torvalds 9991da177e4SLinus Torvalds void unregister_rpc_pipefs(void) 10001da177e4SLinus Torvalds { 10011a1d92c1SAlexey Dobriyan kmem_cache_destroy(rpc_inode_cachep); 10021da177e4SLinus Torvalds unregister_filesystem(&rpc_pipe_fs_type); 10031da177e4SLinus Torvalds } 1004