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 791da177e4SLinus Torvalds int 801da177e4SLinus Torvalds rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) 811da177e4SLinus Torvalds { 821da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 836070fe6fSTrond Myklebust int res = -EPIPE; 841da177e4SLinus Torvalds 859842ef35STrond Myklebust spin_lock(&inode->i_lock); 866070fe6fSTrond Myklebust if (rpci->ops == NULL) 876070fe6fSTrond Myklebust goto out; 881da177e4SLinus Torvalds if (rpci->nreaders) { 891da177e4SLinus Torvalds list_add_tail(&msg->list, &rpci->pipe); 901da177e4SLinus Torvalds rpci->pipelen += msg->len; 916070fe6fSTrond Myklebust res = 0; 921da177e4SLinus Torvalds } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) { 931da177e4SLinus Torvalds if (list_empty(&rpci->pipe)) 9424c5d9d7STrond Myklebust queue_delayed_work(rpciod_workqueue, 9524c5d9d7STrond Myklebust &rpci->queue_timeout, 961da177e4SLinus Torvalds RPC_UPCALL_TIMEOUT); 971da177e4SLinus Torvalds list_add_tail(&msg->list, &rpci->pipe); 981da177e4SLinus Torvalds rpci->pipelen += msg->len; 996070fe6fSTrond Myklebust res = 0; 1006070fe6fSTrond Myklebust } 1016070fe6fSTrond Myklebust out: 1029842ef35STrond Myklebust spin_unlock(&inode->i_lock); 1031da177e4SLinus Torvalds wake_up(&rpci->waitq); 1041da177e4SLinus Torvalds return res; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1076070fe6fSTrond Myklebust static inline void 1086070fe6fSTrond Myklebust rpc_inode_setowner(struct inode *inode, void *private) 1096070fe6fSTrond Myklebust { 1106070fe6fSTrond Myklebust RPC_I(inode)->private = private; 1116070fe6fSTrond Myklebust } 1126070fe6fSTrond Myklebust 1131da177e4SLinus Torvalds static void 1141da177e4SLinus Torvalds rpc_close_pipes(struct inode *inode) 1151da177e4SLinus Torvalds { 1161da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 1179842ef35STrond Myklebust struct rpc_pipe_ops *ops; 1181da177e4SLinus Torvalds 1191b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 1209842ef35STrond Myklebust ops = rpci->ops; 1219842ef35STrond Myklebust if (ops != NULL) { 1229842ef35STrond Myklebust LIST_HEAD(free_list); 1239842ef35STrond Myklebust 1249842ef35STrond Myklebust spin_lock(&inode->i_lock); 1251da177e4SLinus Torvalds rpci->nreaders = 0; 1269842ef35STrond Myklebust list_splice_init(&rpci->in_upcall, &free_list); 1279842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 1289842ef35STrond Myklebust rpci->pipelen = 0; 1291da177e4SLinus Torvalds rpci->ops = NULL; 1309842ef35STrond Myklebust spin_unlock(&inode->i_lock); 1319842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); 1329842ef35STrond Myklebust rpci->nwriters = 0; 1339842ef35STrond Myklebust if (ops->release_pipe) 1349842ef35STrond Myklebust ops->release_pipe(inode); 1354011cd97STrond Myklebust cancel_delayed_work_sync(&rpci->queue_timeout); 1361da177e4SLinus Torvalds } 1376070fe6fSTrond Myklebust rpc_inode_setowner(inode, NULL); 1381b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds static struct inode * 1421da177e4SLinus Torvalds rpc_alloc_inode(struct super_block *sb) 1431da177e4SLinus Torvalds { 1441da177e4SLinus Torvalds struct rpc_inode *rpci; 145e94b1766SChristoph Lameter rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); 1461da177e4SLinus Torvalds if (!rpci) 1471da177e4SLinus Torvalds return NULL; 1481da177e4SLinus Torvalds return &rpci->vfs_inode; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static void 1521da177e4SLinus Torvalds rpc_destroy_inode(struct inode *inode) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds kmem_cache_free(rpc_inode_cachep, RPC_I(inode)); 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds static int 1581da177e4SLinus Torvalds rpc_pipe_open(struct inode *inode, struct file *filp) 1591da177e4SLinus Torvalds { 1601da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 1611da177e4SLinus Torvalds int res = -ENXIO; 1621da177e4SLinus Torvalds 1631b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 1641da177e4SLinus Torvalds if (rpci->ops != NULL) { 1651da177e4SLinus Torvalds if (filp->f_mode & FMODE_READ) 1661da177e4SLinus Torvalds rpci->nreaders ++; 1671da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 1681da177e4SLinus Torvalds rpci->nwriters ++; 1691da177e4SLinus Torvalds res = 0; 1701da177e4SLinus Torvalds } 1711b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 1721da177e4SLinus Torvalds return res; 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds static int 1761da177e4SLinus Torvalds rpc_pipe_release(struct inode *inode, struct file *filp) 1771da177e4SLinus Torvalds { 178969b7f25STrond Myklebust struct rpc_inode *rpci = RPC_I(inode); 1791da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 1801da177e4SLinus Torvalds 1811b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 1821da177e4SLinus Torvalds if (rpci->ops == NULL) 1831da177e4SLinus Torvalds goto out; 1841da177e4SLinus Torvalds msg = (struct rpc_pipe_msg *)filp->private_data; 1851da177e4SLinus Torvalds if (msg != NULL) { 1869842ef35STrond Myklebust spin_lock(&inode->i_lock); 18748e49187STrond Myklebust msg->errno = -EAGAIN; 1889842ef35STrond Myklebust list_del(&msg->list); 1899842ef35STrond Myklebust spin_unlock(&inode->i_lock); 1901da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 1931da177e4SLinus Torvalds rpci->nwriters --; 1949842ef35STrond Myklebust if (filp->f_mode & FMODE_READ) { 1951da177e4SLinus Torvalds rpci->nreaders --; 1969842ef35STrond Myklebust if (rpci->nreaders == 0) { 1979842ef35STrond Myklebust LIST_HEAD(free_list); 1989842ef35STrond Myklebust spin_lock(&inode->i_lock); 1999842ef35STrond Myklebust list_splice_init(&rpci->pipe, &free_list); 2009842ef35STrond Myklebust rpci->pipelen = 0; 2019842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2029842ef35STrond Myklebust rpc_purge_list(rpci, &free_list, 2039842ef35STrond Myklebust rpci->ops->destroy_msg, -EAGAIN); 2049842ef35STrond Myklebust } 2059842ef35STrond Myklebust } 2061da177e4SLinus Torvalds if (rpci->ops->release_pipe) 2071da177e4SLinus Torvalds rpci->ops->release_pipe(inode); 2081da177e4SLinus Torvalds out: 2091b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2101da177e4SLinus Torvalds return 0; 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds static ssize_t 2141da177e4SLinus Torvalds rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) 2151da177e4SLinus Torvalds { 216303b46bbSJosef Sipek struct inode *inode = filp->f_path.dentry->d_inode; 2171da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 2181da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 2191da177e4SLinus Torvalds int res = 0; 2201da177e4SLinus Torvalds 2211b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2221da177e4SLinus Torvalds if (rpci->ops == NULL) { 2231da177e4SLinus Torvalds res = -EPIPE; 2241da177e4SLinus Torvalds goto out_unlock; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds msg = filp->private_data; 2271da177e4SLinus Torvalds if (msg == NULL) { 2289842ef35STrond Myklebust spin_lock(&inode->i_lock); 2291da177e4SLinus Torvalds if (!list_empty(&rpci->pipe)) { 2301da177e4SLinus Torvalds msg = list_entry(rpci->pipe.next, 2311da177e4SLinus Torvalds struct rpc_pipe_msg, 2321da177e4SLinus Torvalds list); 2331da177e4SLinus Torvalds list_move(&msg->list, &rpci->in_upcall); 2341da177e4SLinus Torvalds rpci->pipelen -= msg->len; 2351da177e4SLinus Torvalds filp->private_data = msg; 2361da177e4SLinus Torvalds msg->copied = 0; 2371da177e4SLinus Torvalds } 2389842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2391da177e4SLinus Torvalds if (msg == NULL) 2401da177e4SLinus Torvalds goto out_unlock; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds /* NOTE: it is up to the callback to update msg->copied */ 2431da177e4SLinus Torvalds res = rpci->ops->upcall(filp, msg, buf, len); 2441da177e4SLinus Torvalds if (res < 0 || msg->len == msg->copied) { 2451da177e4SLinus Torvalds filp->private_data = NULL; 2469842ef35STrond Myklebust spin_lock(&inode->i_lock); 2479842ef35STrond Myklebust list_del(&msg->list); 2489842ef35STrond Myklebust spin_unlock(&inode->i_lock); 2491da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds out_unlock: 2521b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2531da177e4SLinus Torvalds return res; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds static ssize_t 2571da177e4SLinus Torvalds rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) 2581da177e4SLinus Torvalds { 259303b46bbSJosef Sipek struct inode *inode = filp->f_path.dentry->d_inode; 2601da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 2611da177e4SLinus Torvalds int res; 2621da177e4SLinus Torvalds 2631b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2641da177e4SLinus Torvalds res = -EPIPE; 2651da177e4SLinus Torvalds if (rpci->ops != NULL) 2661da177e4SLinus Torvalds res = rpci->ops->downcall(filp, buf, len); 2671b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2681da177e4SLinus Torvalds return res; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds static unsigned int 2721da177e4SLinus Torvalds rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) 2731da177e4SLinus Torvalds { 2741da177e4SLinus Torvalds struct rpc_inode *rpci; 2751da177e4SLinus Torvalds unsigned int mask = 0; 2761da177e4SLinus Torvalds 277303b46bbSJosef Sipek rpci = RPC_I(filp->f_path.dentry->d_inode); 2781da177e4SLinus Torvalds poll_wait(filp, &rpci->waitq, wait); 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds mask = POLLOUT | POLLWRNORM; 2811da177e4SLinus Torvalds if (rpci->ops == NULL) 2821da177e4SLinus Torvalds mask |= POLLERR | POLLHUP; 283eda4f9b7SJ. Bruce Fields if (filp->private_data || !list_empty(&rpci->pipe)) 2841da177e4SLinus Torvalds mask |= POLLIN | POLLRDNORM; 2851da177e4SLinus Torvalds return mask; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds static int 2891da177e4SLinus Torvalds rpc_pipe_ioctl(struct inode *ino, struct file *filp, 2901da177e4SLinus Torvalds unsigned int cmd, unsigned long arg) 2911da177e4SLinus Torvalds { 292303b46bbSJosef Sipek struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); 2931da177e4SLinus Torvalds int len; 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds switch (cmd) { 2961da177e4SLinus Torvalds case FIONREAD: 2971da177e4SLinus Torvalds if (rpci->ops == NULL) 2981da177e4SLinus Torvalds return -EPIPE; 2991da177e4SLinus Torvalds len = rpci->pipelen; 3001da177e4SLinus Torvalds if (filp->private_data) { 3011da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 3021da177e4SLinus Torvalds msg = (struct rpc_pipe_msg *)filp->private_data; 3031da177e4SLinus Torvalds len += msg->len - msg->copied; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds return put_user(len, (int __user *)arg); 3061da177e4SLinus Torvalds default: 3071da177e4SLinus Torvalds return -EINVAL; 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 311da7071d7SArjan van de Ven static const struct file_operations rpc_pipe_fops = { 3121da177e4SLinus Torvalds .owner = THIS_MODULE, 3131da177e4SLinus Torvalds .llseek = no_llseek, 3141da177e4SLinus Torvalds .read = rpc_pipe_read, 3151da177e4SLinus Torvalds .write = rpc_pipe_write, 3161da177e4SLinus Torvalds .poll = rpc_pipe_poll, 3171da177e4SLinus Torvalds .ioctl = rpc_pipe_ioctl, 3181da177e4SLinus Torvalds .open = rpc_pipe_open, 3191da177e4SLinus Torvalds .release = rpc_pipe_release, 3201da177e4SLinus Torvalds }; 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds static int 3231da177e4SLinus Torvalds rpc_show_info(struct seq_file *m, void *v) 3241da177e4SLinus Torvalds { 3251da177e4SLinus Torvalds struct rpc_clnt *clnt = m->private; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds seq_printf(m, "RPC server: %s\n", clnt->cl_server); 3281da177e4SLinus Torvalds seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, 3291da177e4SLinus Torvalds clnt->cl_prog, clnt->cl_vers); 330e7f78657SChuck Lever seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); 331e7f78657SChuck Lever seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); 332bf19aaceSJ. Bruce Fields seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); 3331da177e4SLinus Torvalds return 0; 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds static int 3371da177e4SLinus Torvalds rpc_info_open(struct inode *inode, struct file *file) 3381da177e4SLinus Torvalds { 3391da177e4SLinus Torvalds struct rpc_clnt *clnt; 3401da177e4SLinus Torvalds int ret = single_open(file, rpc_show_info, NULL); 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds if (!ret) { 3431da177e4SLinus Torvalds struct seq_file *m = file->private_data; 3441b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 3451da177e4SLinus Torvalds clnt = RPC_I(inode)->private; 3461da177e4SLinus Torvalds if (clnt) { 34734f52e35STrond Myklebust kref_get(&clnt->cl_kref); 3481da177e4SLinus Torvalds m->private = clnt; 3491da177e4SLinus Torvalds } else { 3501da177e4SLinus Torvalds single_release(inode, file); 3511da177e4SLinus Torvalds ret = -EINVAL; 3521da177e4SLinus Torvalds } 3531b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds return ret; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds static int 3591da177e4SLinus Torvalds rpc_info_release(struct inode *inode, struct file *file) 3601da177e4SLinus Torvalds { 3611da177e4SLinus Torvalds struct seq_file *m = file->private_data; 3621da177e4SLinus Torvalds struct rpc_clnt *clnt = (struct rpc_clnt *)m->private; 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds if (clnt) 3651da177e4SLinus Torvalds rpc_release_client(clnt); 3661da177e4SLinus Torvalds return single_release(inode, file); 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 369da7071d7SArjan van de Ven static const struct file_operations rpc_info_operations = { 3701da177e4SLinus Torvalds .owner = THIS_MODULE, 3711da177e4SLinus Torvalds .open = rpc_info_open, 3721da177e4SLinus Torvalds .read = seq_read, 3731da177e4SLinus Torvalds .llseek = seq_lseek, 3741da177e4SLinus Torvalds .release = rpc_info_release, 3751da177e4SLinus Torvalds }; 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds /* 3791da177e4SLinus Torvalds * We have a single directory with 1 node in it. 3801da177e4SLinus Torvalds */ 3811da177e4SLinus Torvalds enum { 3821da177e4SLinus Torvalds RPCAUTH_Root = 1, 3831da177e4SLinus Torvalds RPCAUTH_lockd, 3841da177e4SLinus Torvalds RPCAUTH_mount, 3851da177e4SLinus Torvalds RPCAUTH_nfs, 3861da177e4SLinus Torvalds RPCAUTH_portmap, 3871da177e4SLinus Torvalds RPCAUTH_statd, 3881da177e4SLinus Torvalds RPCAUTH_RootEOF 3891da177e4SLinus Torvalds }; 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds /* 3921da177e4SLinus Torvalds * Description of fs contents. 3931da177e4SLinus Torvalds */ 3941da177e4SLinus Torvalds struct rpc_filelist { 3951da177e4SLinus Torvalds char *name; 39699ac48f5SArjan van de Ven const struct file_operations *i_fop; 3971da177e4SLinus Torvalds int mode; 3981da177e4SLinus Torvalds }; 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds static struct rpc_filelist files[] = { 4011da177e4SLinus Torvalds [RPCAUTH_lockd] = { 4021da177e4SLinus Torvalds .name = "lockd", 4031da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 4041da177e4SLinus Torvalds }, 4051da177e4SLinus Torvalds [RPCAUTH_mount] = { 4061da177e4SLinus Torvalds .name = "mount", 4071da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 4081da177e4SLinus Torvalds }, 4091da177e4SLinus Torvalds [RPCAUTH_nfs] = { 4101da177e4SLinus Torvalds .name = "nfs", 4111da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 4121da177e4SLinus Torvalds }, 4131da177e4SLinus Torvalds [RPCAUTH_portmap] = { 4141da177e4SLinus Torvalds .name = "portmap", 4151da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 4161da177e4SLinus Torvalds }, 4171da177e4SLinus Torvalds [RPCAUTH_statd] = { 4181da177e4SLinus Torvalds .name = "statd", 4191da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 4201da177e4SLinus Torvalds }, 4211da177e4SLinus Torvalds }; 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds enum { 4241da177e4SLinus Torvalds RPCAUTH_info = 2, 4251da177e4SLinus Torvalds RPCAUTH_EOF 4261da177e4SLinus Torvalds }; 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds static struct rpc_filelist authfiles[] = { 4291da177e4SLinus Torvalds [RPCAUTH_info] = { 4301da177e4SLinus Torvalds .name = "info", 4311da177e4SLinus Torvalds .i_fop = &rpc_info_operations, 4321da177e4SLinus Torvalds .mode = S_IFREG | S_IRUSR, 4331da177e4SLinus Torvalds }, 4341da177e4SLinus Torvalds }; 4351da177e4SLinus Torvalds 43654281548STrond Myklebust struct vfsmount *rpc_get_mount(void) 4371da177e4SLinus Torvalds { 43854281548STrond Myklebust int err; 43954281548STrond Myklebust 4401f5ce9e9STrond Myklebust err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mount, &rpc_mount_count); 44154281548STrond Myklebust if (err != 0) 44254281548STrond Myklebust return ERR_PTR(err); 44354281548STrond Myklebust return rpc_mount; 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 44654281548STrond Myklebust void rpc_put_mount(void) 4471da177e4SLinus Torvalds { 4481da177e4SLinus Torvalds simple_release_fs(&rpc_mount, &rpc_mount_count); 4491da177e4SLinus Torvalds } 4501da177e4SLinus Torvalds 45162e1761cSTrond Myklebust static int rpc_delete_dentry(struct dentry *dentry) 45262e1761cSTrond Myklebust { 45362e1761cSTrond Myklebust return 1; 45462e1761cSTrond Myklebust } 45562e1761cSTrond Myklebust 45662e1761cSTrond Myklebust static struct dentry_operations rpc_dentry_operations = { 45762e1761cSTrond Myklebust .d_delete = rpc_delete_dentry, 45862e1761cSTrond Myklebust }; 45962e1761cSTrond Myklebust 460f134585aSTrond Myklebust static int 461f134585aSTrond Myklebust rpc_lookup_parent(char *path, struct nameidata *nd) 462f134585aSTrond Myklebust { 4634ac4efc1SJosef 'Jeff' Sipek struct vfsmount *mnt; 4644ac4efc1SJosef 'Jeff' Sipek 465f134585aSTrond Myklebust if (path[0] == '\0') 466f134585aSTrond Myklebust return -ENOENT; 4674ac4efc1SJosef 'Jeff' Sipek 4684ac4efc1SJosef 'Jeff' Sipek mnt = rpc_get_mount(); 4694ac4efc1SJosef 'Jeff' Sipek if (IS_ERR(mnt)) { 470f134585aSTrond Myklebust printk(KERN_WARNING "%s: %s failed to mount " 471f134585aSTrond Myklebust "pseudofilesystem \n", __FILE__, __FUNCTION__); 4724ac4efc1SJosef 'Jeff' Sipek return PTR_ERR(mnt); 473f134585aSTrond Myklebust } 474f134585aSTrond Myklebust 4754ac4efc1SJosef 'Jeff' Sipek if (vfs_path_lookup(mnt->mnt_root, mnt, path, LOOKUP_PARENT, nd)) { 476f134585aSTrond Myklebust printk(KERN_WARNING "%s: %s failed to find path %s\n", 477f134585aSTrond Myklebust __FILE__, __FUNCTION__, path); 478f134585aSTrond Myklebust rpc_put_mount(); 479f134585aSTrond Myklebust return -ENOENT; 480f134585aSTrond Myklebust } 481f134585aSTrond Myklebust return 0; 482f134585aSTrond Myklebust } 483f134585aSTrond Myklebust 484f134585aSTrond Myklebust static void 485f134585aSTrond Myklebust rpc_release_path(struct nameidata *nd) 486f134585aSTrond Myklebust { 487f134585aSTrond Myklebust path_release(nd); 488f134585aSTrond Myklebust rpc_put_mount(); 489f134585aSTrond Myklebust } 490f134585aSTrond Myklebust 4911da177e4SLinus Torvalds static struct inode * 4921da177e4SLinus Torvalds rpc_get_inode(struct super_block *sb, int mode) 4931da177e4SLinus Torvalds { 4941da177e4SLinus Torvalds struct inode *inode = new_inode(sb); 4951da177e4SLinus Torvalds if (!inode) 4961da177e4SLinus Torvalds return NULL; 4971da177e4SLinus Torvalds inode->i_mode = mode; 4981da177e4SLinus Torvalds inode->i_uid = inode->i_gid = 0; 4991da177e4SLinus Torvalds inode->i_blocks = 0; 5001da177e4SLinus Torvalds inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 5011da177e4SLinus Torvalds switch(mode & S_IFMT) { 5021da177e4SLinus Torvalds case S_IFDIR: 5031da177e4SLinus Torvalds inode->i_fop = &simple_dir_operations; 5041da177e4SLinus Torvalds inode->i_op = &simple_dir_inode_operations; 505d8c76e6fSDave Hansen inc_nlink(inode); 5061da177e4SLinus Torvalds default: 5071da177e4SLinus Torvalds break; 5081da177e4SLinus Torvalds } 5091da177e4SLinus Torvalds return inode; 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds /* 5131da177e4SLinus Torvalds * FIXME: This probably has races. 5141da177e4SLinus Torvalds */ 5151da177e4SLinus Torvalds static void 51662e1761cSTrond Myklebust rpc_depopulate(struct dentry *parent, int start, int eof) 5171da177e4SLinus Torvalds { 5181da177e4SLinus Torvalds struct inode *dir = parent->d_inode; 5191da177e4SLinus Torvalds struct list_head *pos, *next; 5201da177e4SLinus Torvalds struct dentry *dentry, *dvec[10]; 5211da177e4SLinus Torvalds int n = 0; 5221da177e4SLinus Torvalds 523c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD); 5241da177e4SLinus Torvalds repeat: 5251da177e4SLinus Torvalds spin_lock(&dcache_lock); 5261da177e4SLinus Torvalds list_for_each_safe(pos, next, &parent->d_subdirs) { 5275160ee6fSEric Dumazet dentry = list_entry(pos, struct dentry, d_u.d_child); 52862e1761cSTrond Myklebust if (!dentry->d_inode || 52962e1761cSTrond Myklebust dentry->d_inode->i_ino < start || 53062e1761cSTrond Myklebust dentry->d_inode->i_ino >= eof) 53162e1761cSTrond Myklebust continue; 5321da177e4SLinus Torvalds spin_lock(&dentry->d_lock); 5331da177e4SLinus Torvalds if (!d_unhashed(dentry)) { 5341da177e4SLinus Torvalds dget_locked(dentry); 5351da177e4SLinus Torvalds __d_drop(dentry); 5361da177e4SLinus Torvalds spin_unlock(&dentry->d_lock); 5371da177e4SLinus Torvalds dvec[n++] = dentry; 5381da177e4SLinus Torvalds if (n == ARRAY_SIZE(dvec)) 5391da177e4SLinus Torvalds break; 5401da177e4SLinus Torvalds } else 5411da177e4SLinus Torvalds spin_unlock(&dentry->d_lock); 5421da177e4SLinus Torvalds } 5431da177e4SLinus Torvalds spin_unlock(&dcache_lock); 5441da177e4SLinus Torvalds if (n) { 5451da177e4SLinus Torvalds do { 5461da177e4SLinus Torvalds dentry = dvec[--n]; 54762e1761cSTrond Myklebust if (S_ISREG(dentry->d_inode->i_mode)) 5481da177e4SLinus Torvalds simple_unlink(dir, dentry); 54962e1761cSTrond Myklebust else if (S_ISDIR(dentry->d_inode->i_mode)) 55062e1761cSTrond Myklebust simple_rmdir(dir, dentry); 55162e1761cSTrond Myklebust d_delete(dentry); 5521da177e4SLinus Torvalds dput(dentry); 5531da177e4SLinus Torvalds } while (n); 5541da177e4SLinus Torvalds goto repeat; 5551da177e4SLinus Torvalds } 5561b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds static int 5601da177e4SLinus Torvalds rpc_populate(struct dentry *parent, 5611da177e4SLinus Torvalds struct rpc_filelist *files, 5621da177e4SLinus Torvalds int start, int eof) 5631da177e4SLinus Torvalds { 5641da177e4SLinus Torvalds struct inode *inode, *dir = parent->d_inode; 5651da177e4SLinus Torvalds void *private = RPC_I(dir)->private; 5661da177e4SLinus Torvalds struct dentry *dentry; 5671da177e4SLinus Torvalds int mode, i; 5681da177e4SLinus Torvalds 5691b1dcc1bSJes Sorensen mutex_lock(&dir->i_mutex); 5701da177e4SLinus Torvalds for (i = start; i < eof; i++) { 5711da177e4SLinus Torvalds dentry = d_alloc_name(parent, files[i].name); 5721da177e4SLinus Torvalds if (!dentry) 5731da177e4SLinus Torvalds goto out_bad; 57462e1761cSTrond Myklebust dentry->d_op = &rpc_dentry_operations; 5751da177e4SLinus Torvalds mode = files[i].mode; 5761da177e4SLinus Torvalds inode = rpc_get_inode(dir->i_sb, mode); 5771da177e4SLinus Torvalds if (!inode) { 5781da177e4SLinus Torvalds dput(dentry); 5791da177e4SLinus Torvalds goto out_bad; 5801da177e4SLinus Torvalds } 5811da177e4SLinus Torvalds inode->i_ino = i; 5821da177e4SLinus Torvalds if (files[i].i_fop) 5831da177e4SLinus Torvalds inode->i_fop = files[i].i_fop; 5841da177e4SLinus Torvalds if (private) 5851da177e4SLinus Torvalds rpc_inode_setowner(inode, private); 5861da177e4SLinus Torvalds if (S_ISDIR(mode)) 587d8c76e6fSDave Hansen inc_nlink(dir); 5881da177e4SLinus Torvalds d_add(dentry, inode); 58950e437d5STrond Myklebust fsnotify_create(dir, dentry); 5901da177e4SLinus Torvalds } 5911b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 5921da177e4SLinus Torvalds return 0; 5931da177e4SLinus Torvalds out_bad: 5941b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 5951da177e4SLinus Torvalds printk(KERN_WARNING "%s: %s failed to populate directory %s\n", 5961da177e4SLinus Torvalds __FILE__, __FUNCTION__, parent->d_name.name); 5971da177e4SLinus Torvalds return -ENOMEM; 5981da177e4SLinus Torvalds } 5991da177e4SLinus Torvalds 600f134585aSTrond Myklebust static int 601f134585aSTrond Myklebust __rpc_mkdir(struct inode *dir, struct dentry *dentry) 6021da177e4SLinus Torvalds { 6031da177e4SLinus Torvalds struct inode *inode; 6041da177e4SLinus Torvalds 6051d21632dSTrond Myklebust inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); 6061da177e4SLinus Torvalds if (!inode) 607f134585aSTrond Myklebust goto out_err; 6081da177e4SLinus Torvalds inode->i_ino = iunique(dir->i_sb, 100); 609278c995cSChristoph Hellwig d_instantiate(dentry, inode); 610d8c76e6fSDave Hansen inc_nlink(dir); 61150e437d5STrond Myklebust fsnotify_mkdir(dir, dentry); 612f134585aSTrond Myklebust return 0; 613f134585aSTrond Myklebust out_err: 614f134585aSTrond Myklebust printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", 615f134585aSTrond Myklebust __FILE__, __FUNCTION__, dentry->d_name.name); 616f134585aSTrond Myklebust return -ENOMEM; 617278c995cSChristoph Hellwig } 618278c995cSChristoph Hellwig 619f134585aSTrond Myklebust static int 620f134585aSTrond Myklebust __rpc_rmdir(struct inode *dir, struct dentry *dentry) 621278c995cSChristoph Hellwig { 622f134585aSTrond Myklebust int error; 62362e1761cSTrond Myklebust error = simple_rmdir(dir, dentry); 62462e1761cSTrond Myklebust if (!error) 62562e1761cSTrond Myklebust d_delete(dentry); 626f134585aSTrond Myklebust return error; 627f134585aSTrond Myklebust } 628f134585aSTrond Myklebust 629f134585aSTrond Myklebust static struct dentry * 63034f30896STrond Myklebust rpc_lookup_create(struct dentry *parent, const char *name, int len, int exclusive) 631f134585aSTrond Myklebust { 632158998b6STrond Myklebust struct inode *dir = parent->d_inode; 633f134585aSTrond Myklebust struct dentry *dentry; 634f134585aSTrond Myklebust 635c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 636158998b6STrond Myklebust dentry = lookup_one_len(name, parent, len); 637f134585aSTrond Myklebust if (IS_ERR(dentry)) 638f134585aSTrond Myklebust goto out_err; 63962e1761cSTrond Myklebust if (!dentry->d_inode) 64062e1761cSTrond Myklebust dentry->d_op = &rpc_dentry_operations; 64162e1761cSTrond Myklebust else if (exclusive) { 642f134585aSTrond Myklebust dput(dentry); 643f134585aSTrond Myklebust dentry = ERR_PTR(-EEXIST); 644f134585aSTrond Myklebust goto out_err; 645f134585aSTrond Myklebust } 646f134585aSTrond Myklebust return dentry; 647f134585aSTrond Myklebust out_err: 6481b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 649158998b6STrond Myklebust return dentry; 650158998b6STrond Myklebust } 651158998b6STrond Myklebust 652158998b6STrond Myklebust static struct dentry * 653158998b6STrond Myklebust rpc_lookup_negative(char *path, struct nameidata *nd) 654158998b6STrond Myklebust { 655158998b6STrond Myklebust struct dentry *dentry; 656158998b6STrond Myklebust int error; 657158998b6STrond Myklebust 658158998b6STrond Myklebust if ((error = rpc_lookup_parent(path, nd)) != 0) 659158998b6STrond Myklebust return ERR_PTR(error); 66034f30896STrond Myklebust dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len, 1); 661158998b6STrond Myklebust if (IS_ERR(dentry)) 662f134585aSTrond Myklebust rpc_release_path(nd); 663f134585aSTrond Myklebust return dentry; 664f134585aSTrond Myklebust } 665f134585aSTrond Myklebust 666f134585aSTrond Myklebust 667f134585aSTrond Myklebust struct dentry * 668f134585aSTrond Myklebust rpc_mkdir(char *path, struct rpc_clnt *rpc_client) 669f134585aSTrond Myklebust { 670f134585aSTrond Myklebust struct nameidata nd; 671f134585aSTrond Myklebust struct dentry *dentry; 672f134585aSTrond Myklebust struct inode *dir; 673f134585aSTrond Myklebust int error; 674f134585aSTrond Myklebust 675f134585aSTrond Myklebust dentry = rpc_lookup_negative(path, &nd); 676f134585aSTrond Myklebust if (IS_ERR(dentry)) 677f134585aSTrond Myklebust return dentry; 678f134585aSTrond Myklebust dir = nd.dentry->d_inode; 679f134585aSTrond Myklebust if ((error = __rpc_mkdir(dir, dentry)) != 0) 680f134585aSTrond Myklebust goto err_dput; 681f134585aSTrond Myklebust RPC_I(dentry->d_inode)->private = rpc_client; 682f134585aSTrond Myklebust error = rpc_populate(dentry, authfiles, 683f134585aSTrond Myklebust RPCAUTH_info, RPCAUTH_EOF); 684f134585aSTrond Myklebust if (error) 685f134585aSTrond Myklebust goto err_depopulate; 6865c3e985aSTrond Myklebust dget(dentry); 687f134585aSTrond Myklebust out: 6881b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 689f134585aSTrond Myklebust rpc_release_path(&nd); 6905c3e985aSTrond Myklebust return dentry; 691f134585aSTrond Myklebust err_depopulate: 69262e1761cSTrond Myklebust rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); 693f134585aSTrond Myklebust __rpc_rmdir(dir, dentry); 694f134585aSTrond Myklebust err_dput: 695f134585aSTrond Myklebust dput(dentry); 696f134585aSTrond Myklebust printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", 697f134585aSTrond Myklebust __FILE__, __FUNCTION__, path, error); 698f134585aSTrond Myklebust dentry = ERR_PTR(error); 699f134585aSTrond Myklebust goto out; 700f134585aSTrond Myklebust } 701f134585aSTrond Myklebust 702f134585aSTrond Myklebust int 703dff02cc1STrond Myklebust rpc_rmdir(struct dentry *dentry) 704f134585aSTrond Myklebust { 705dff02cc1STrond Myklebust struct dentry *parent; 706f134585aSTrond Myklebust struct inode *dir; 707f134585aSTrond Myklebust int error; 708f134585aSTrond Myklebust 709dff02cc1STrond Myklebust parent = dget_parent(dentry); 710dff02cc1STrond Myklebust dir = parent->d_inode; 711c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 71262e1761cSTrond Myklebust rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); 713f134585aSTrond Myklebust error = __rpc_rmdir(dir, dentry); 714f134585aSTrond Myklebust dput(dentry); 7151b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 716dff02cc1STrond Myklebust dput(parent); 717f134585aSTrond Myklebust return error; 718f134585aSTrond Myklebust } 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds struct dentry * 721158998b6STrond Myklebust rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags) 7221da177e4SLinus Torvalds { 7231da177e4SLinus Torvalds struct dentry *dentry; 724f134585aSTrond Myklebust struct inode *dir, *inode; 7251da177e4SLinus Torvalds struct rpc_inode *rpci; 7261da177e4SLinus Torvalds 72734f30896STrond Myklebust dentry = rpc_lookup_create(parent, name, strlen(name), 0); 7281da177e4SLinus Torvalds if (IS_ERR(dentry)) 729f134585aSTrond Myklebust return dentry; 730158998b6STrond Myklebust dir = parent->d_inode; 73134f30896STrond Myklebust if (dentry->d_inode) { 73234f30896STrond Myklebust rpci = RPC_I(dentry->d_inode); 73334f30896STrond Myklebust if (rpci->private != private || 73434f30896STrond Myklebust rpci->ops != ops || 73534f30896STrond Myklebust rpci->flags != flags) { 73634f30896STrond Myklebust dput (dentry); 73734f30896STrond Myklebust dentry = ERR_PTR(-EBUSY); 73834f30896STrond Myklebust } 73903a1256fSTrond Myklebust rpci->nkern_readwriters++; 74034f30896STrond Myklebust goto out; 74134f30896STrond Myklebust } 742a53a3c58SSteve Dickson inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR); 743f134585aSTrond Myklebust if (!inode) 744f134585aSTrond Myklebust goto err_dput; 7451da177e4SLinus Torvalds inode->i_ino = iunique(dir->i_sb, 100); 7461da177e4SLinus Torvalds inode->i_fop = &rpc_pipe_fops; 747f134585aSTrond Myklebust d_instantiate(dentry, inode); 7481da177e4SLinus Torvalds rpci = RPC_I(inode); 7491da177e4SLinus Torvalds rpci->private = private; 7501da177e4SLinus Torvalds rpci->flags = flags; 7511da177e4SLinus Torvalds rpci->ops = ops; 75203a1256fSTrond Myklebust rpci->nkern_readwriters = 1; 75350e437d5STrond Myklebust fsnotify_create(dir, dentry); 7545c3e985aSTrond Myklebust dget(dentry); 755f134585aSTrond Myklebust out: 7561b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 7575c3e985aSTrond Myklebust return dentry; 758f134585aSTrond Myklebust err_dput: 7591da177e4SLinus Torvalds dput(dentry); 760f134585aSTrond Myklebust dentry = ERR_PTR(-ENOMEM); 761158998b6STrond Myklebust printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", 762158998b6STrond Myklebust __FILE__, __FUNCTION__, parent->d_name.name, name, 763158998b6STrond Myklebust -ENOMEM); 764f134585aSTrond Myklebust goto out; 7651da177e4SLinus Torvalds } 7661da177e4SLinus Torvalds 767f134585aSTrond Myklebust int 7685d67476fSTrond Myklebust rpc_unlink(struct dentry *dentry) 7691da177e4SLinus Torvalds { 7705d67476fSTrond Myklebust struct dentry *parent; 771f134585aSTrond Myklebust struct inode *dir; 7725d67476fSTrond Myklebust int error = 0; 7731da177e4SLinus Torvalds 7745d67476fSTrond Myklebust parent = dget_parent(dentry); 7755d67476fSTrond Myklebust dir = parent->d_inode; 776c6573c29SArjan van de Ven mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); 77703a1256fSTrond Myklebust if (--RPC_I(dentry->d_inode)->nkern_readwriters == 0) { 7781da177e4SLinus Torvalds rpc_close_pipes(dentry->d_inode); 779f134585aSTrond Myklebust error = simple_unlink(dir, dentry); 78062e1761cSTrond Myklebust if (!error) 78162e1761cSTrond Myklebust d_delete(dentry); 78203a1256fSTrond Myklebust } 78368adb0afSTrond Myklebust dput(dentry); 7841b1dcc1bSJes Sorensen mutex_unlock(&dir->i_mutex); 7855d67476fSTrond Myklebust dput(parent); 786f134585aSTrond Myklebust return error; 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds /* 7901da177e4SLinus Torvalds * populate the filesystem 7911da177e4SLinus Torvalds */ 7921da177e4SLinus Torvalds static struct super_operations s_ops = { 7931da177e4SLinus Torvalds .alloc_inode = rpc_alloc_inode, 7941da177e4SLinus Torvalds .destroy_inode = rpc_destroy_inode, 7951da177e4SLinus Torvalds .statfs = simple_statfs, 7961da177e4SLinus Torvalds }; 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds #define RPCAUTH_GSSMAGIC 0x67596969 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds static int 8011da177e4SLinus Torvalds rpc_fill_super(struct super_block *sb, void *data, int silent) 8021da177e4SLinus Torvalds { 8031da177e4SLinus Torvalds struct inode *inode; 8041da177e4SLinus Torvalds struct dentry *root; 8051da177e4SLinus Torvalds 8061da177e4SLinus Torvalds sb->s_blocksize = PAGE_CACHE_SIZE; 8071da177e4SLinus Torvalds sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 8081da177e4SLinus Torvalds sb->s_magic = RPCAUTH_GSSMAGIC; 8091da177e4SLinus Torvalds sb->s_op = &s_ops; 8101da177e4SLinus Torvalds sb->s_time_gran = 1; 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds inode = rpc_get_inode(sb, S_IFDIR | 0755); 8131da177e4SLinus Torvalds if (!inode) 8141da177e4SLinus Torvalds return -ENOMEM; 8151da177e4SLinus Torvalds root = d_alloc_root(inode); 8161da177e4SLinus Torvalds if (!root) { 8171da177e4SLinus Torvalds iput(inode); 8181da177e4SLinus Torvalds return -ENOMEM; 8191da177e4SLinus Torvalds } 8201da177e4SLinus Torvalds if (rpc_populate(root, files, RPCAUTH_Root + 1, RPCAUTH_RootEOF)) 8211da177e4SLinus Torvalds goto out; 8221da177e4SLinus Torvalds sb->s_root = root; 8231da177e4SLinus Torvalds return 0; 8241da177e4SLinus Torvalds out: 8251da177e4SLinus Torvalds d_genocide(root); 8261da177e4SLinus Torvalds dput(root); 8271da177e4SLinus Torvalds return -ENOMEM; 8281da177e4SLinus Torvalds } 8291da177e4SLinus Torvalds 830454e2398SDavid Howells static int 8311da177e4SLinus Torvalds rpc_get_sb(struct file_system_type *fs_type, 832454e2398SDavid Howells int flags, const char *dev_name, void *data, struct vfsmount *mnt) 8331da177e4SLinus Torvalds { 834454e2398SDavid Howells return get_sb_single(fs_type, flags, data, rpc_fill_super, mnt); 8351da177e4SLinus Torvalds } 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type = { 8381da177e4SLinus Torvalds .owner = THIS_MODULE, 8391da177e4SLinus Torvalds .name = "rpc_pipefs", 8401da177e4SLinus Torvalds .get_sb = rpc_get_sb, 8411da177e4SLinus Torvalds .kill_sb = kill_litter_super, 8421da177e4SLinus Torvalds }; 8431da177e4SLinus Torvalds 8441da177e4SLinus Torvalds static void 8454ba9b9d0SChristoph Lameter init_once(struct kmem_cache * cachep, void *foo) 8461da177e4SLinus Torvalds { 8471da177e4SLinus Torvalds struct rpc_inode *rpci = (struct rpc_inode *) foo; 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds inode_init_once(&rpci->vfs_inode); 8501da177e4SLinus Torvalds rpci->private = NULL; 8511da177e4SLinus Torvalds rpci->nreaders = 0; 8521da177e4SLinus Torvalds rpci->nwriters = 0; 8531da177e4SLinus Torvalds INIT_LIST_HEAD(&rpci->in_upcall); 8546e84c7b6STrond Myklebust INIT_LIST_HEAD(&rpci->in_downcall); 8551da177e4SLinus Torvalds INIT_LIST_HEAD(&rpci->pipe); 8561da177e4SLinus Torvalds rpci->pipelen = 0; 8571da177e4SLinus Torvalds init_waitqueue_head(&rpci->waitq); 85852bad64dSDavid Howells INIT_DELAYED_WORK(&rpci->queue_timeout, 85965f27f38SDavid Howells rpc_timeout_upcall_queue); 8601da177e4SLinus Torvalds rpci->ops = NULL; 8611da177e4SLinus Torvalds } 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds int register_rpc_pipefs(void) 8641da177e4SLinus Torvalds { 8655bd5f581SAkinobu Mita int err; 8665bd5f581SAkinobu Mita 8671da177e4SLinus Torvalds rpc_inode_cachep = kmem_cache_create("rpc_inode_cache", 8681da177e4SLinus Torvalds sizeof(struct rpc_inode), 869fffb60f9SPaul Jackson 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| 870fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 87120c2df83SPaul Mundt init_once); 8721da177e4SLinus Torvalds if (!rpc_inode_cachep) 8731da177e4SLinus Torvalds return -ENOMEM; 8745bd5f581SAkinobu Mita err = register_filesystem(&rpc_pipe_fs_type); 8755bd5f581SAkinobu Mita if (err) { 8765bd5f581SAkinobu Mita kmem_cache_destroy(rpc_inode_cachep); 8775bd5f581SAkinobu Mita return err; 8785bd5f581SAkinobu Mita } 8795bd5f581SAkinobu Mita 8801da177e4SLinus Torvalds return 0; 8811da177e4SLinus Torvalds } 8821da177e4SLinus Torvalds 8831da177e4SLinus Torvalds void unregister_rpc_pipefs(void) 8841da177e4SLinus Torvalds { 8851a1d92c1SAlexey Dobriyan kmem_cache_destroy(rpc_inode_cachep); 8861da177e4SLinus Torvalds unregister_filesystem(&rpc_pipe_fs_type); 8871da177e4SLinus Torvalds } 888