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/config.h> 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/slab.h> 141da177e4SLinus Torvalds #include <linux/string.h> 151da177e4SLinus Torvalds #include <linux/pagemap.h> 161da177e4SLinus Torvalds #include <linux/mount.h> 171da177e4SLinus Torvalds #include <linux/namei.h> 181da177e4SLinus Torvalds #include <linux/dnotify.h> 191da177e4SLinus Torvalds #include <linux/kernel.h> 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #include <asm/ioctls.h> 221da177e4SLinus Torvalds #include <linux/fs.h> 231da177e4SLinus Torvalds #include <linux/poll.h> 241da177e4SLinus Torvalds #include <linux/wait.h> 251da177e4SLinus Torvalds #include <linux/seq_file.h> 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 281da177e4SLinus Torvalds #include <linux/workqueue.h> 291da177e4SLinus Torvalds #include <linux/sunrpc/rpc_pipe_fs.h> 301da177e4SLinus Torvalds 31ba89966cSEric Dumazet static struct vfsmount *rpc_mount __read_mostly; 321da177e4SLinus Torvalds static int rpc_mount_count; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type; 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds 37ba89966cSEric Dumazet static kmem_cache_t *rpc_inode_cachep __read_mostly; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds #define RPC_UPCALL_TIMEOUT (30*HZ) 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds static void 421da177e4SLinus Torvalds __rpc_purge_upcall(struct inode *inode, int err) 431da177e4SLinus Torvalds { 441da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 451da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds while (!list_empty(&rpci->pipe)) { 481da177e4SLinus Torvalds msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, list); 491da177e4SLinus Torvalds list_del_init(&msg->list); 501da177e4SLinus Torvalds msg->errno = err; 511da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds while (!list_empty(&rpci->in_upcall)) { 541da177e4SLinus Torvalds msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, list); 551da177e4SLinus Torvalds list_del_init(&msg->list); 561da177e4SLinus Torvalds msg->errno = err; 571da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds rpci->pipelen = 0; 601da177e4SLinus Torvalds wake_up(&rpci->waitq); 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds static void 641da177e4SLinus Torvalds rpc_timeout_upcall_queue(void *data) 651da177e4SLinus Torvalds { 661da177e4SLinus Torvalds struct rpc_inode *rpci = (struct rpc_inode *)data; 671da177e4SLinus Torvalds struct inode *inode = &rpci->vfs_inode; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds down(&inode->i_sem); 701da177e4SLinus Torvalds if (rpci->nreaders == 0 && !list_empty(&rpci->pipe)) 711da177e4SLinus Torvalds __rpc_purge_upcall(inode, -ETIMEDOUT); 721da177e4SLinus Torvalds up(&inode->i_sem); 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds int 761da177e4SLinus Torvalds rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) 771da177e4SLinus Torvalds { 781da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 791da177e4SLinus Torvalds int res = 0; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds down(&inode->i_sem); 821da177e4SLinus Torvalds if (rpci->nreaders) { 831da177e4SLinus Torvalds list_add_tail(&msg->list, &rpci->pipe); 841da177e4SLinus Torvalds rpci->pipelen += msg->len; 851da177e4SLinus Torvalds } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) { 861da177e4SLinus Torvalds if (list_empty(&rpci->pipe)) 871da177e4SLinus Torvalds schedule_delayed_work(&rpci->queue_timeout, 881da177e4SLinus Torvalds RPC_UPCALL_TIMEOUT); 891da177e4SLinus Torvalds list_add_tail(&msg->list, &rpci->pipe); 901da177e4SLinus Torvalds rpci->pipelen += msg->len; 911da177e4SLinus Torvalds } else 921da177e4SLinus Torvalds res = -EPIPE; 931da177e4SLinus Torvalds up(&inode->i_sem); 941da177e4SLinus Torvalds wake_up(&rpci->waitq); 951da177e4SLinus Torvalds return res; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds static void 991da177e4SLinus Torvalds rpc_close_pipes(struct inode *inode) 1001da177e4SLinus Torvalds { 1011da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds cancel_delayed_work(&rpci->queue_timeout); 1041da177e4SLinus Torvalds flush_scheduled_work(); 1051da177e4SLinus Torvalds down(&inode->i_sem); 1061da177e4SLinus Torvalds if (rpci->ops != NULL) { 1071da177e4SLinus Torvalds rpci->nreaders = 0; 1081da177e4SLinus Torvalds __rpc_purge_upcall(inode, -EPIPE); 1091da177e4SLinus Torvalds rpci->nwriters = 0; 1101da177e4SLinus Torvalds if (rpci->ops->release_pipe) 1111da177e4SLinus Torvalds rpci->ops->release_pipe(inode); 1121da177e4SLinus Torvalds rpci->ops = NULL; 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds up(&inode->i_sem); 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds static inline void 1181da177e4SLinus Torvalds rpc_inode_setowner(struct inode *inode, void *private) 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds RPC_I(inode)->private = private; 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds static struct inode * 1241da177e4SLinus Torvalds rpc_alloc_inode(struct super_block *sb) 1251da177e4SLinus Torvalds { 1261da177e4SLinus Torvalds struct rpc_inode *rpci; 1271da177e4SLinus Torvalds rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, SLAB_KERNEL); 1281da177e4SLinus Torvalds if (!rpci) 1291da177e4SLinus Torvalds return NULL; 1301da177e4SLinus Torvalds return &rpci->vfs_inode; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds static void 1341da177e4SLinus Torvalds rpc_destroy_inode(struct inode *inode) 1351da177e4SLinus Torvalds { 1361da177e4SLinus Torvalds kmem_cache_free(rpc_inode_cachep, RPC_I(inode)); 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds static int 1401da177e4SLinus Torvalds rpc_pipe_open(struct inode *inode, struct file *filp) 1411da177e4SLinus Torvalds { 1421da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 1431da177e4SLinus Torvalds int res = -ENXIO; 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds down(&inode->i_sem); 1461da177e4SLinus Torvalds if (rpci->ops != NULL) { 1471da177e4SLinus Torvalds if (filp->f_mode & FMODE_READ) 1481da177e4SLinus Torvalds rpci->nreaders ++; 1491da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 1501da177e4SLinus Torvalds rpci->nwriters ++; 1511da177e4SLinus Torvalds res = 0; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds up(&inode->i_sem); 1541da177e4SLinus Torvalds return res; 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds static int 1581da177e4SLinus Torvalds rpc_pipe_release(struct inode *inode, struct file *filp) 1591da177e4SLinus Torvalds { 1601da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode); 1611da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds down(&inode->i_sem); 1641da177e4SLinus Torvalds if (rpci->ops == NULL) 1651da177e4SLinus Torvalds goto out; 1661da177e4SLinus Torvalds msg = (struct rpc_pipe_msg *)filp->private_data; 1671da177e4SLinus Torvalds if (msg != NULL) { 1681da177e4SLinus Torvalds msg->errno = -EPIPE; 1691da177e4SLinus Torvalds list_del_init(&msg->list); 1701da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 1711da177e4SLinus Torvalds } 1721da177e4SLinus Torvalds if (filp->f_mode & FMODE_WRITE) 1731da177e4SLinus Torvalds rpci->nwriters --; 1741da177e4SLinus Torvalds if (filp->f_mode & FMODE_READ) 1751da177e4SLinus Torvalds rpci->nreaders --; 1761da177e4SLinus Torvalds if (!rpci->nreaders) 1771da177e4SLinus Torvalds __rpc_purge_upcall(inode, -EPIPE); 1781da177e4SLinus Torvalds if (rpci->ops->release_pipe) 1791da177e4SLinus Torvalds rpci->ops->release_pipe(inode); 1801da177e4SLinus Torvalds out: 1811da177e4SLinus Torvalds up(&inode->i_sem); 1821da177e4SLinus Torvalds return 0; 1831da177e4SLinus Torvalds } 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds static ssize_t 1861da177e4SLinus Torvalds rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) 1871da177e4SLinus Torvalds { 1881da177e4SLinus Torvalds struct inode *inode = filp->f_dentry->d_inode; 1891da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 1901da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 1911da177e4SLinus Torvalds int res = 0; 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds down(&inode->i_sem); 1941da177e4SLinus Torvalds if (rpci->ops == NULL) { 1951da177e4SLinus Torvalds res = -EPIPE; 1961da177e4SLinus Torvalds goto out_unlock; 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds msg = filp->private_data; 1991da177e4SLinus Torvalds if (msg == NULL) { 2001da177e4SLinus Torvalds if (!list_empty(&rpci->pipe)) { 2011da177e4SLinus Torvalds msg = list_entry(rpci->pipe.next, 2021da177e4SLinus Torvalds struct rpc_pipe_msg, 2031da177e4SLinus Torvalds list); 2041da177e4SLinus Torvalds list_move(&msg->list, &rpci->in_upcall); 2051da177e4SLinus Torvalds rpci->pipelen -= msg->len; 2061da177e4SLinus Torvalds filp->private_data = msg; 2071da177e4SLinus Torvalds msg->copied = 0; 2081da177e4SLinus Torvalds } 2091da177e4SLinus Torvalds if (msg == NULL) 2101da177e4SLinus Torvalds goto out_unlock; 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds /* NOTE: it is up to the callback to update msg->copied */ 2131da177e4SLinus Torvalds res = rpci->ops->upcall(filp, msg, buf, len); 2141da177e4SLinus Torvalds if (res < 0 || msg->len == msg->copied) { 2151da177e4SLinus Torvalds filp->private_data = NULL; 2161da177e4SLinus Torvalds list_del_init(&msg->list); 2171da177e4SLinus Torvalds rpci->ops->destroy_msg(msg); 2181da177e4SLinus Torvalds } 2191da177e4SLinus Torvalds out_unlock: 2201da177e4SLinus Torvalds up(&inode->i_sem); 2211da177e4SLinus Torvalds return res; 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds static ssize_t 2251da177e4SLinus Torvalds rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) 2261da177e4SLinus Torvalds { 2271da177e4SLinus Torvalds struct inode *inode = filp->f_dentry->d_inode; 2281da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(inode); 2291da177e4SLinus Torvalds int res; 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds down(&inode->i_sem); 2321da177e4SLinus Torvalds res = -EPIPE; 2331da177e4SLinus Torvalds if (rpci->ops != NULL) 2341da177e4SLinus Torvalds res = rpci->ops->downcall(filp, buf, len); 2351da177e4SLinus Torvalds up(&inode->i_sem); 2361da177e4SLinus Torvalds return res; 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds static unsigned int 2401da177e4SLinus Torvalds rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) 2411da177e4SLinus Torvalds { 2421da177e4SLinus Torvalds struct rpc_inode *rpci; 2431da177e4SLinus Torvalds unsigned int mask = 0; 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds rpci = RPC_I(filp->f_dentry->d_inode); 2461da177e4SLinus Torvalds poll_wait(filp, &rpci->waitq, wait); 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds mask = POLLOUT | POLLWRNORM; 2491da177e4SLinus Torvalds if (rpci->ops == NULL) 2501da177e4SLinus Torvalds mask |= POLLERR | POLLHUP; 2511da177e4SLinus Torvalds if (!list_empty(&rpci->pipe)) 2521da177e4SLinus Torvalds mask |= POLLIN | POLLRDNORM; 2531da177e4SLinus Torvalds return mask; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds static int 2571da177e4SLinus Torvalds rpc_pipe_ioctl(struct inode *ino, struct file *filp, 2581da177e4SLinus Torvalds unsigned int cmd, unsigned long arg) 2591da177e4SLinus Torvalds { 2601da177e4SLinus Torvalds struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode); 2611da177e4SLinus Torvalds int len; 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds switch (cmd) { 2641da177e4SLinus Torvalds case FIONREAD: 2651da177e4SLinus Torvalds if (rpci->ops == NULL) 2661da177e4SLinus Torvalds return -EPIPE; 2671da177e4SLinus Torvalds len = rpci->pipelen; 2681da177e4SLinus Torvalds if (filp->private_data) { 2691da177e4SLinus Torvalds struct rpc_pipe_msg *msg; 2701da177e4SLinus Torvalds msg = (struct rpc_pipe_msg *)filp->private_data; 2711da177e4SLinus Torvalds len += msg->len - msg->copied; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds return put_user(len, (int __user *)arg); 2741da177e4SLinus Torvalds default: 2751da177e4SLinus Torvalds return -EINVAL; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds static struct file_operations rpc_pipe_fops = { 2801da177e4SLinus Torvalds .owner = THIS_MODULE, 2811da177e4SLinus Torvalds .llseek = no_llseek, 2821da177e4SLinus Torvalds .read = rpc_pipe_read, 2831da177e4SLinus Torvalds .write = rpc_pipe_write, 2841da177e4SLinus Torvalds .poll = rpc_pipe_poll, 2851da177e4SLinus Torvalds .ioctl = rpc_pipe_ioctl, 2861da177e4SLinus Torvalds .open = rpc_pipe_open, 2871da177e4SLinus Torvalds .release = rpc_pipe_release, 2881da177e4SLinus Torvalds }; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds static int 2911da177e4SLinus Torvalds rpc_show_info(struct seq_file *m, void *v) 2921da177e4SLinus Torvalds { 2931da177e4SLinus Torvalds struct rpc_clnt *clnt = m->private; 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds seq_printf(m, "RPC server: %s\n", clnt->cl_server); 2961da177e4SLinus Torvalds seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, 2971da177e4SLinus Torvalds clnt->cl_prog, clnt->cl_vers); 2981da177e4SLinus Torvalds seq_printf(m, "address: %u.%u.%u.%u\n", 2991da177e4SLinus Torvalds NIPQUAD(clnt->cl_xprt->addr.sin_addr.s_addr)); 3001da177e4SLinus Torvalds seq_printf(m, "protocol: %s\n", 3011da177e4SLinus Torvalds clnt->cl_xprt->prot == IPPROTO_UDP ? "udp" : "tcp"); 3021da177e4SLinus Torvalds return 0; 3031da177e4SLinus Torvalds } 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds static int 3061da177e4SLinus Torvalds rpc_info_open(struct inode *inode, struct file *file) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds struct rpc_clnt *clnt; 3091da177e4SLinus Torvalds int ret = single_open(file, rpc_show_info, NULL); 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds if (!ret) { 3121da177e4SLinus Torvalds struct seq_file *m = file->private_data; 3131da177e4SLinus Torvalds down(&inode->i_sem); 3141da177e4SLinus Torvalds clnt = RPC_I(inode)->private; 3151da177e4SLinus Torvalds if (clnt) { 3161da177e4SLinus Torvalds atomic_inc(&clnt->cl_users); 3171da177e4SLinus Torvalds m->private = clnt; 3181da177e4SLinus Torvalds } else { 3191da177e4SLinus Torvalds single_release(inode, file); 3201da177e4SLinus Torvalds ret = -EINVAL; 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds up(&inode->i_sem); 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds return ret; 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds static int 3281da177e4SLinus Torvalds rpc_info_release(struct inode *inode, struct file *file) 3291da177e4SLinus Torvalds { 3301da177e4SLinus Torvalds struct seq_file *m = file->private_data; 3311da177e4SLinus Torvalds struct rpc_clnt *clnt = (struct rpc_clnt *)m->private; 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds if (clnt) 3341da177e4SLinus Torvalds rpc_release_client(clnt); 3351da177e4SLinus Torvalds return single_release(inode, file); 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds static struct file_operations rpc_info_operations = { 3391da177e4SLinus Torvalds .owner = THIS_MODULE, 3401da177e4SLinus Torvalds .open = rpc_info_open, 3411da177e4SLinus Torvalds .read = seq_read, 3421da177e4SLinus Torvalds .llseek = seq_lseek, 3431da177e4SLinus Torvalds .release = rpc_info_release, 3441da177e4SLinus Torvalds }; 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds /* 3481da177e4SLinus Torvalds * We have a single directory with 1 node in it. 3491da177e4SLinus Torvalds */ 3501da177e4SLinus Torvalds enum { 3511da177e4SLinus Torvalds RPCAUTH_Root = 1, 3521da177e4SLinus Torvalds RPCAUTH_lockd, 3531da177e4SLinus Torvalds RPCAUTH_mount, 3541da177e4SLinus Torvalds RPCAUTH_nfs, 3551da177e4SLinus Torvalds RPCAUTH_portmap, 3561da177e4SLinus Torvalds RPCAUTH_statd, 3571da177e4SLinus Torvalds RPCAUTH_RootEOF 3581da177e4SLinus Torvalds }; 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds /* 3611da177e4SLinus Torvalds * Description of fs contents. 3621da177e4SLinus Torvalds */ 3631da177e4SLinus Torvalds struct rpc_filelist { 3641da177e4SLinus Torvalds char *name; 3651da177e4SLinus Torvalds struct file_operations *i_fop; 3661da177e4SLinus Torvalds int mode; 3671da177e4SLinus Torvalds }; 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds static struct rpc_filelist files[] = { 3701da177e4SLinus Torvalds [RPCAUTH_lockd] = { 3711da177e4SLinus Torvalds .name = "lockd", 3721da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 3731da177e4SLinus Torvalds }, 3741da177e4SLinus Torvalds [RPCAUTH_mount] = { 3751da177e4SLinus Torvalds .name = "mount", 3761da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 3771da177e4SLinus Torvalds }, 3781da177e4SLinus Torvalds [RPCAUTH_nfs] = { 3791da177e4SLinus Torvalds .name = "nfs", 3801da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 3811da177e4SLinus Torvalds }, 3821da177e4SLinus Torvalds [RPCAUTH_portmap] = { 3831da177e4SLinus Torvalds .name = "portmap", 3841da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 3851da177e4SLinus Torvalds }, 3861da177e4SLinus Torvalds [RPCAUTH_statd] = { 3871da177e4SLinus Torvalds .name = "statd", 3881da177e4SLinus Torvalds .mode = S_IFDIR | S_IRUGO | S_IXUGO, 3891da177e4SLinus Torvalds }, 3901da177e4SLinus Torvalds }; 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds enum { 3931da177e4SLinus Torvalds RPCAUTH_info = 2, 3941da177e4SLinus Torvalds RPCAUTH_EOF 3951da177e4SLinus Torvalds }; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds static struct rpc_filelist authfiles[] = { 3981da177e4SLinus Torvalds [RPCAUTH_info] = { 3991da177e4SLinus Torvalds .name = "info", 4001da177e4SLinus Torvalds .i_fop = &rpc_info_operations, 4011da177e4SLinus Torvalds .mode = S_IFREG | S_IRUSR, 4021da177e4SLinus Torvalds }, 4031da177e4SLinus Torvalds }; 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds static int 4061da177e4SLinus Torvalds rpc_get_mount(void) 4071da177e4SLinus Torvalds { 4081da177e4SLinus Torvalds return simple_pin_fs("rpc_pipefs", &rpc_mount, &rpc_mount_count); 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds static void 4121da177e4SLinus Torvalds rpc_put_mount(void) 4131da177e4SLinus Torvalds { 4141da177e4SLinus Torvalds simple_release_fs(&rpc_mount, &rpc_mount_count); 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds static struct inode * 4181da177e4SLinus Torvalds rpc_get_inode(struct super_block *sb, int mode) 4191da177e4SLinus Torvalds { 4201da177e4SLinus Torvalds struct inode *inode = new_inode(sb); 4211da177e4SLinus Torvalds if (!inode) 4221da177e4SLinus Torvalds return NULL; 4231da177e4SLinus Torvalds inode->i_mode = mode; 4241da177e4SLinus Torvalds inode->i_uid = inode->i_gid = 0; 4251da177e4SLinus Torvalds inode->i_blksize = PAGE_CACHE_SIZE; 4261da177e4SLinus Torvalds inode->i_blocks = 0; 4271da177e4SLinus Torvalds inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 4281da177e4SLinus Torvalds switch(mode & S_IFMT) { 4291da177e4SLinus Torvalds case S_IFDIR: 4301da177e4SLinus Torvalds inode->i_fop = &simple_dir_operations; 4311da177e4SLinus Torvalds inode->i_op = &simple_dir_inode_operations; 4321da177e4SLinus Torvalds inode->i_nlink++; 4331da177e4SLinus Torvalds default: 4341da177e4SLinus Torvalds break; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds return inode; 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds /* 4401da177e4SLinus Torvalds * FIXME: This probably has races. 4411da177e4SLinus Torvalds */ 4421da177e4SLinus Torvalds static void 4431da177e4SLinus Torvalds rpc_depopulate(struct dentry *parent) 4441da177e4SLinus Torvalds { 4451da177e4SLinus Torvalds struct inode *dir = parent->d_inode; 4461da177e4SLinus Torvalds struct list_head *pos, *next; 4471da177e4SLinus Torvalds struct dentry *dentry, *dvec[10]; 4481da177e4SLinus Torvalds int n = 0; 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds down(&dir->i_sem); 4511da177e4SLinus Torvalds repeat: 4521da177e4SLinus Torvalds spin_lock(&dcache_lock); 4531da177e4SLinus Torvalds list_for_each_safe(pos, next, &parent->d_subdirs) { 4541da177e4SLinus Torvalds dentry = list_entry(pos, struct dentry, d_child); 4551da177e4SLinus Torvalds spin_lock(&dentry->d_lock); 4561da177e4SLinus Torvalds if (!d_unhashed(dentry)) { 4571da177e4SLinus Torvalds dget_locked(dentry); 4581da177e4SLinus Torvalds __d_drop(dentry); 4591da177e4SLinus Torvalds spin_unlock(&dentry->d_lock); 4601da177e4SLinus Torvalds dvec[n++] = dentry; 4611da177e4SLinus Torvalds if (n == ARRAY_SIZE(dvec)) 4621da177e4SLinus Torvalds break; 4631da177e4SLinus Torvalds } else 4641da177e4SLinus Torvalds spin_unlock(&dentry->d_lock); 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds spin_unlock(&dcache_lock); 4671da177e4SLinus Torvalds if (n) { 4681da177e4SLinus Torvalds do { 4691da177e4SLinus Torvalds dentry = dvec[--n]; 4701da177e4SLinus Torvalds if (dentry->d_inode) { 4711da177e4SLinus Torvalds rpc_close_pipes(dentry->d_inode); 4721da177e4SLinus Torvalds rpc_inode_setowner(dentry->d_inode, NULL); 4731da177e4SLinus Torvalds simple_unlink(dir, dentry); 4741da177e4SLinus Torvalds } 4751da177e4SLinus Torvalds dput(dentry); 4761da177e4SLinus Torvalds } while (n); 4771da177e4SLinus Torvalds goto repeat; 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds up(&dir->i_sem); 4801da177e4SLinus Torvalds } 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds static int 4831da177e4SLinus Torvalds rpc_populate(struct dentry *parent, 4841da177e4SLinus Torvalds struct rpc_filelist *files, 4851da177e4SLinus Torvalds int start, int eof) 4861da177e4SLinus Torvalds { 4871da177e4SLinus Torvalds struct inode *inode, *dir = parent->d_inode; 4881da177e4SLinus Torvalds void *private = RPC_I(dir)->private; 4891da177e4SLinus Torvalds struct dentry *dentry; 4901da177e4SLinus Torvalds int mode, i; 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds down(&dir->i_sem); 4931da177e4SLinus Torvalds for (i = start; i < eof; i++) { 4941da177e4SLinus Torvalds dentry = d_alloc_name(parent, files[i].name); 4951da177e4SLinus Torvalds if (!dentry) 4961da177e4SLinus Torvalds goto out_bad; 4971da177e4SLinus Torvalds mode = files[i].mode; 4981da177e4SLinus Torvalds inode = rpc_get_inode(dir->i_sb, mode); 4991da177e4SLinus Torvalds if (!inode) { 5001da177e4SLinus Torvalds dput(dentry); 5011da177e4SLinus Torvalds goto out_bad; 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds inode->i_ino = i; 5041da177e4SLinus Torvalds if (files[i].i_fop) 5051da177e4SLinus Torvalds inode->i_fop = files[i].i_fop; 5061da177e4SLinus Torvalds if (private) 5071da177e4SLinus Torvalds rpc_inode_setowner(inode, private); 5081da177e4SLinus Torvalds if (S_ISDIR(mode)) 5091da177e4SLinus Torvalds dir->i_nlink++; 5101da177e4SLinus Torvalds d_add(dentry, inode); 5111da177e4SLinus Torvalds } 5121da177e4SLinus Torvalds up(&dir->i_sem); 5131da177e4SLinus Torvalds return 0; 5141da177e4SLinus Torvalds out_bad: 5151da177e4SLinus Torvalds up(&dir->i_sem); 5161da177e4SLinus Torvalds printk(KERN_WARNING "%s: %s failed to populate directory %s\n", 5171da177e4SLinus Torvalds __FILE__, __FUNCTION__, parent->d_name.name); 5181da177e4SLinus Torvalds return -ENOMEM; 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds 521278c995cSChristoph Hellwig struct dentry * 522278c995cSChristoph Hellwig rpc_mkdir(struct dentry *parent, char *name, struct rpc_clnt *rpc_client) 5231da177e4SLinus Torvalds { 524278c995cSChristoph Hellwig struct inode *dir; 525278c995cSChristoph Hellwig struct dentry *dentry; 5261da177e4SLinus Torvalds struct inode *inode; 527278c995cSChristoph Hellwig int error; 528278c995cSChristoph Hellwig 529278c995cSChristoph Hellwig if (!parent) 530278c995cSChristoph Hellwig parent = rpc_mount->mnt_root; 531278c995cSChristoph Hellwig 532278c995cSChristoph Hellwig dir = parent->d_inode; 533278c995cSChristoph Hellwig 534278c995cSChristoph Hellwig error = rpc_get_mount(); 535278c995cSChristoph Hellwig if (error) 536278c995cSChristoph Hellwig return ERR_PTR(error); 537278c995cSChristoph Hellwig 538278c995cSChristoph Hellwig down(&dir->i_sem); 539278c995cSChristoph Hellwig dentry = lookup_one_len(name, parent, strlen(name)); 540278c995cSChristoph Hellwig if (IS_ERR(dentry)) 541278c995cSChristoph Hellwig goto out_unlock; 542278c995cSChristoph Hellwig if (dentry->d_inode) { 543278c995cSChristoph Hellwig dentry = ERR_PTR(-EEXIST); 544278c995cSChristoph Hellwig goto out_dput; 545278c995cSChristoph Hellwig } 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUSR | S_IXUSR); 5481da177e4SLinus Torvalds if (!inode) 549278c995cSChristoph Hellwig goto out_dput; 5501da177e4SLinus Torvalds inode->i_ino = iunique(dir->i_sb, 100); 5511da177e4SLinus Torvalds dir->i_nlink++; 5521da177e4SLinus Torvalds RPC_I(dentry->d_inode)->private = rpc_client; 553278c995cSChristoph Hellwig 554278c995cSChristoph Hellwig d_instantiate(dentry, inode); 555278c995cSChristoph Hellwig dget(dentry); 556278c995cSChristoph Hellwig up(&dir->i_sem); 557278c995cSChristoph Hellwig 558278c995cSChristoph Hellwig inode_dir_notify(dir, DN_CREATE); 559278c995cSChristoph Hellwig 5601da177e4SLinus Torvalds error = rpc_populate(dentry, authfiles, 5611da177e4SLinus Torvalds RPCAUTH_info, RPCAUTH_EOF); 5621da177e4SLinus Torvalds if (error) 563278c995cSChristoph Hellwig goto out_depopulate; 564278c995cSChristoph Hellwig 5651da177e4SLinus Torvalds return dentry; 5661da177e4SLinus Torvalds 567278c995cSChristoph Hellwig out_depopulate: 568278c995cSChristoph Hellwig rpc_rmdir(dentry); 569278c995cSChristoph Hellwig out_dput: 5701da177e4SLinus Torvalds dput(dentry); 571278c995cSChristoph Hellwig out_unlock: 5721da177e4SLinus Torvalds up(&dir->i_sem); 573278c995cSChristoph Hellwig rpc_put_mount(); 574278c995cSChristoph Hellwig return dentry; 575278c995cSChristoph Hellwig } 576278c995cSChristoph Hellwig 577278c995cSChristoph Hellwig void 578278c995cSChristoph Hellwig rpc_rmdir(struct dentry *dentry) 579278c995cSChristoph Hellwig { 580278c995cSChristoph Hellwig struct dentry *parent = dentry->d_parent; 581278c995cSChristoph Hellwig 582278c995cSChristoph Hellwig rpc_depopulate(dentry); 583278c995cSChristoph Hellwig 584278c995cSChristoph Hellwig down(&parent->d_inode->i_sem); 585278c995cSChristoph Hellwig if (dentry->d_inode) { 586278c995cSChristoph Hellwig rpc_close_pipes(dentry->d_inode); 587278c995cSChristoph Hellwig rpc_inode_setowner(dentry->d_inode, NULL); 588278c995cSChristoph Hellwig simple_rmdir(parent->d_inode, dentry); 589278c995cSChristoph Hellwig } 590278c995cSChristoph Hellwig up(&parent->d_inode->i_sem); 591278c995cSChristoph Hellwig 592278c995cSChristoph Hellwig inode_dir_notify(parent->d_inode, DN_DELETE); 593278c995cSChristoph Hellwig rpc_put_mount(); 5941da177e4SLinus Torvalds } 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds struct dentry * 597278c995cSChristoph Hellwig rpc_mkpipe(struct dentry *parent, char *name, void *private, 598278c995cSChristoph Hellwig struct rpc_pipe_ops *ops, int flags) 5991da177e4SLinus Torvalds { 600278c995cSChristoph Hellwig struct inode *dir = parent->d_inode; 6011da177e4SLinus Torvalds struct dentry *dentry; 602278c995cSChristoph Hellwig struct inode *inode; 6031da177e4SLinus Torvalds struct rpc_inode *rpci; 604278c995cSChristoph Hellwig int error; 6051da177e4SLinus Torvalds 606278c995cSChristoph Hellwig error = rpc_get_mount(); 607278c995cSChristoph Hellwig if (error) 608278c995cSChristoph Hellwig return ERR_PTR(error); 609278c995cSChristoph Hellwig 610278c995cSChristoph Hellwig down(&parent->d_inode->i_sem); 611278c995cSChristoph Hellwig dentry = lookup_one_len(name, parent, strlen(name)); 6121da177e4SLinus Torvalds if (IS_ERR(dentry)) 613278c995cSChristoph Hellwig goto out_unlock; 614278c995cSChristoph Hellwig if (dentry->d_inode) { 615278c995cSChristoph Hellwig dentry = ERR_PTR(-EEXIST); 616278c995cSChristoph Hellwig goto out_dput; 617278c995cSChristoph Hellwig } 618278c995cSChristoph Hellwig 619278c995cSChristoph Hellwig inode = rpc_get_inode(parent->d_inode->i_sb, 620278c995cSChristoph Hellwig S_IFSOCK | S_IRUSR | S_IWUSR); 621278c995cSChristoph Hellwig if (!inode) { 622278c995cSChristoph Hellwig dentry = ERR_PTR(-ENOMEM); 623278c995cSChristoph Hellwig goto out_dput; 624278c995cSChristoph Hellwig } 625278c995cSChristoph Hellwig 6261da177e4SLinus Torvalds inode->i_ino = iunique(dir->i_sb, 100); 6271da177e4SLinus Torvalds inode->i_fop = &rpc_pipe_fops; 628278c995cSChristoph Hellwig 6291da177e4SLinus Torvalds rpci = RPC_I(inode); 6301da177e4SLinus Torvalds rpci->private = private; 6311da177e4SLinus Torvalds rpci->flags = flags; 6321da177e4SLinus Torvalds rpci->ops = ops; 633278c995cSChristoph Hellwig 634278c995cSChristoph Hellwig d_instantiate(dentry, inode); 635278c995cSChristoph Hellwig dget(dentry); 636278c995cSChristoph Hellwig up(&parent->d_inode->i_sem); 637278c995cSChristoph Hellwig 6381da177e4SLinus Torvalds inode_dir_notify(dir, DN_CREATE); 6391da177e4SLinus Torvalds return dentry; 640278c995cSChristoph Hellwig 641278c995cSChristoph Hellwig out_dput: 6421da177e4SLinus Torvalds dput(dentry); 643278c995cSChristoph Hellwig out_unlock: 644278c995cSChristoph Hellwig up(&parent->d_inode->i_sem); 645278c995cSChristoph Hellwig rpc_put_mount(); 646278c995cSChristoph Hellwig return dentry; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 649278c995cSChristoph Hellwig void 650278c995cSChristoph Hellwig rpc_unlink(struct dentry *dentry) 6511da177e4SLinus Torvalds { 652278c995cSChristoph Hellwig struct dentry *parent = dentry->d_parent; 6531da177e4SLinus Torvalds 654278c995cSChristoph Hellwig down(&parent->d_inode->i_sem); 6551da177e4SLinus Torvalds if (dentry->d_inode) { 6561da177e4SLinus Torvalds rpc_close_pipes(dentry->d_inode); 6571da177e4SLinus Torvalds rpc_inode_setowner(dentry->d_inode, NULL); 658278c995cSChristoph Hellwig simple_unlink(parent->d_inode, dentry); 6591da177e4SLinus Torvalds } 660278c995cSChristoph Hellwig up(&parent->d_inode->i_sem); 661278c995cSChristoph Hellwig 662278c995cSChristoph Hellwig inode_dir_notify(parent->d_inode, DN_DELETE); 663278c995cSChristoph Hellwig rpc_put_mount(); 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds /* 6671da177e4SLinus Torvalds * populate the filesystem 6681da177e4SLinus Torvalds */ 6691da177e4SLinus Torvalds static struct super_operations s_ops = { 6701da177e4SLinus Torvalds .alloc_inode = rpc_alloc_inode, 6711da177e4SLinus Torvalds .destroy_inode = rpc_destroy_inode, 6721da177e4SLinus Torvalds .statfs = simple_statfs, 6731da177e4SLinus Torvalds }; 6741da177e4SLinus Torvalds 6751da177e4SLinus Torvalds #define RPCAUTH_GSSMAGIC 0x67596969 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds static int 6781da177e4SLinus Torvalds rpc_fill_super(struct super_block *sb, void *data, int silent) 6791da177e4SLinus Torvalds { 6801da177e4SLinus Torvalds struct inode *inode; 6811da177e4SLinus Torvalds struct dentry *root; 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds sb->s_blocksize = PAGE_CACHE_SIZE; 6841da177e4SLinus Torvalds sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 6851da177e4SLinus Torvalds sb->s_magic = RPCAUTH_GSSMAGIC; 6861da177e4SLinus Torvalds sb->s_op = &s_ops; 6871da177e4SLinus Torvalds sb->s_time_gran = 1; 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds inode = rpc_get_inode(sb, S_IFDIR | 0755); 6901da177e4SLinus Torvalds if (!inode) 6911da177e4SLinus Torvalds return -ENOMEM; 6921da177e4SLinus Torvalds root = d_alloc_root(inode); 6931da177e4SLinus Torvalds if (!root) { 6941da177e4SLinus Torvalds iput(inode); 6951da177e4SLinus Torvalds return -ENOMEM; 6961da177e4SLinus Torvalds } 6971da177e4SLinus Torvalds if (rpc_populate(root, files, RPCAUTH_Root + 1, RPCAUTH_RootEOF)) 6981da177e4SLinus Torvalds goto out; 6991da177e4SLinus Torvalds sb->s_root = root; 7001da177e4SLinus Torvalds return 0; 7011da177e4SLinus Torvalds out: 7021da177e4SLinus Torvalds d_genocide(root); 7031da177e4SLinus Torvalds dput(root); 7041da177e4SLinus Torvalds return -ENOMEM; 7051da177e4SLinus Torvalds } 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds static struct super_block * 7081da177e4SLinus Torvalds rpc_get_sb(struct file_system_type *fs_type, 7091da177e4SLinus Torvalds int flags, const char *dev_name, void *data) 7101da177e4SLinus Torvalds { 7111da177e4SLinus Torvalds return get_sb_single(fs_type, flags, data, rpc_fill_super); 7121da177e4SLinus Torvalds } 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds static struct file_system_type rpc_pipe_fs_type = { 7151da177e4SLinus Torvalds .owner = THIS_MODULE, 7161da177e4SLinus Torvalds .name = "rpc_pipefs", 7171da177e4SLinus Torvalds .get_sb = rpc_get_sb, 7181da177e4SLinus Torvalds .kill_sb = kill_litter_super, 7191da177e4SLinus Torvalds }; 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds static void 7221da177e4SLinus Torvalds init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) 7231da177e4SLinus Torvalds { 7241da177e4SLinus Torvalds struct rpc_inode *rpci = (struct rpc_inode *) foo; 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == 7271da177e4SLinus Torvalds SLAB_CTOR_CONSTRUCTOR) { 7281da177e4SLinus Torvalds inode_init_once(&rpci->vfs_inode); 7291da177e4SLinus Torvalds rpci->private = NULL; 7301da177e4SLinus Torvalds rpci->nreaders = 0; 7311da177e4SLinus Torvalds rpci->nwriters = 0; 7321da177e4SLinus Torvalds INIT_LIST_HEAD(&rpci->in_upcall); 7331da177e4SLinus Torvalds INIT_LIST_HEAD(&rpci->pipe); 7341da177e4SLinus Torvalds rpci->pipelen = 0; 7351da177e4SLinus Torvalds init_waitqueue_head(&rpci->waitq); 7361da177e4SLinus Torvalds INIT_WORK(&rpci->queue_timeout, rpc_timeout_upcall_queue, rpci); 7371da177e4SLinus Torvalds rpci->ops = NULL; 7381da177e4SLinus Torvalds } 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds int register_rpc_pipefs(void) 7421da177e4SLinus Torvalds { 7431da177e4SLinus Torvalds rpc_inode_cachep = kmem_cache_create("rpc_inode_cache", 7441da177e4SLinus Torvalds sizeof(struct rpc_inode), 7451da177e4SLinus Torvalds 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, 7461da177e4SLinus Torvalds init_once, NULL); 7471da177e4SLinus Torvalds if (!rpc_inode_cachep) 7481da177e4SLinus Torvalds return -ENOMEM; 7491da177e4SLinus Torvalds register_filesystem(&rpc_pipe_fs_type); 7501da177e4SLinus Torvalds return 0; 7511da177e4SLinus Torvalds } 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds void unregister_rpc_pipefs(void) 7541da177e4SLinus Torvalds { 7551da177e4SLinus Torvalds if (kmem_cache_destroy(rpc_inode_cachep)) 7561da177e4SLinus Torvalds printk(KERN_WARNING "RPC: unable to free inode cache\n"); 7571da177e4SLinus Torvalds unregister_filesystem(&rpc_pipe_fs_type); 7581da177e4SLinus Torvalds } 759