18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * net/sunrpc/rpc_pipe.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Userland/kernel interface for rpcauth_gss. 68c2ecf20Sopenharmony_ci * Code shamelessly plagiarized from fs/nfsd/nfsctl.c 78c2ecf20Sopenharmony_ci * and fs/sysfs/inode.c 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 168c2ecf20Sopenharmony_ci#include <linux/mount.h> 178c2ecf20Sopenharmony_ci#include <linux/fs_context.h> 188c2ecf20Sopenharmony_ci#include <linux/namei.h> 198c2ecf20Sopenharmony_ci#include <linux/fsnotify.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 228c2ecf20Sopenharmony_ci#include <linux/utsname.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <asm/ioctls.h> 258c2ecf20Sopenharmony_ci#include <linux/poll.h> 268c2ecf20Sopenharmony_ci#include <linux/wait.h> 278c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h> 308c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 318c2ecf20Sopenharmony_ci#include <linux/sunrpc/rpc_pipe_fs.h> 328c2ecf20Sopenharmony_ci#include <linux/sunrpc/cache.h> 338c2ecf20Sopenharmony_ci#include <linux/nsproxy.h> 348c2ecf20Sopenharmony_ci#include <linux/notifier.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "netns.h" 378c2ecf20Sopenharmony_ci#include "sunrpc.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define RPCDBG_FACILITY RPCDBG_DEBUG 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic struct file_system_type rpc_pipe_fs_type; 448c2ecf20Sopenharmony_cistatic const struct rpc_pipe_ops gssd_dummy_pipe_ops; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic struct kmem_cache *rpc_inode_cachep __read_mostly; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define RPC_UPCALL_TIMEOUT (30*HZ) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic BLOCKING_NOTIFIER_HEAD(rpc_pipefs_notifier_list); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciint rpc_pipefs_notifier_register(struct notifier_block *nb) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci return blocking_notifier_chain_register(&rpc_pipefs_notifier_list, nb); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_pipefs_notifier_register); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_civoid rpc_pipefs_notifier_unregister(struct notifier_block *nb) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci blocking_notifier_chain_unregister(&rpc_pipefs_notifier_list, nb); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void rpc_purge_list(wait_queue_head_t *waitq, struct list_head *head, 658c2ecf20Sopenharmony_ci void (*destroy_msg)(struct rpc_pipe_msg *), int err) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct rpc_pipe_msg *msg; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (list_empty(head)) 708c2ecf20Sopenharmony_ci return; 718c2ecf20Sopenharmony_ci do { 728c2ecf20Sopenharmony_ci msg = list_entry(head->next, struct rpc_pipe_msg, list); 738c2ecf20Sopenharmony_ci list_del_init(&msg->list); 748c2ecf20Sopenharmony_ci msg->errno = err; 758c2ecf20Sopenharmony_ci destroy_msg(msg); 768c2ecf20Sopenharmony_ci } while (!list_empty(head)); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (waitq) 798c2ecf20Sopenharmony_ci wake_up(waitq); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void 838c2ecf20Sopenharmony_cirpc_timeout_upcall_queue(struct work_struct *work) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci LIST_HEAD(free_list); 868c2ecf20Sopenharmony_ci struct rpc_pipe *pipe = 878c2ecf20Sopenharmony_ci container_of(work, struct rpc_pipe, queue_timeout.work); 888c2ecf20Sopenharmony_ci void (*destroy_msg)(struct rpc_pipe_msg *); 898c2ecf20Sopenharmony_ci struct dentry *dentry; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci spin_lock(&pipe->lock); 928c2ecf20Sopenharmony_ci destroy_msg = pipe->ops->destroy_msg; 938c2ecf20Sopenharmony_ci if (pipe->nreaders == 0) { 948c2ecf20Sopenharmony_ci list_splice_init(&pipe->pipe, &free_list); 958c2ecf20Sopenharmony_ci pipe->pipelen = 0; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci dentry = dget(pipe->dentry); 988c2ecf20Sopenharmony_ci spin_unlock(&pipe->lock); 998c2ecf20Sopenharmony_ci rpc_purge_list(dentry ? &RPC_I(d_inode(dentry))->waitq : NULL, 1008c2ecf20Sopenharmony_ci &free_list, destroy_msg, -ETIMEDOUT); 1018c2ecf20Sopenharmony_ci dput(dentry); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cissize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg, 1058c2ecf20Sopenharmony_ci char __user *dst, size_t buflen) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci char *data = (char *)msg->data + msg->copied; 1088c2ecf20Sopenharmony_ci size_t mlen = min(msg->len - msg->copied, buflen); 1098c2ecf20Sopenharmony_ci unsigned long left; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci left = copy_to_user(dst, data, mlen); 1128c2ecf20Sopenharmony_ci if (left == mlen) { 1138c2ecf20Sopenharmony_ci msg->errno = -EFAULT; 1148c2ecf20Sopenharmony_ci return -EFAULT; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci mlen -= left; 1188c2ecf20Sopenharmony_ci msg->copied += mlen; 1198c2ecf20Sopenharmony_ci msg->errno = 0; 1208c2ecf20Sopenharmony_ci return mlen; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_pipe_generic_upcall); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/** 1258c2ecf20Sopenharmony_ci * rpc_queue_upcall - queue an upcall message to userspace 1268c2ecf20Sopenharmony_ci * @pipe: upcall pipe on which to queue given message 1278c2ecf20Sopenharmony_ci * @msg: message to queue 1288c2ecf20Sopenharmony_ci * 1298c2ecf20Sopenharmony_ci * Call with an @inode created by rpc_mkpipe() to queue an upcall. 1308c2ecf20Sopenharmony_ci * A userspace process may then later read the upcall by performing a 1318c2ecf20Sopenharmony_ci * read on an open file for this inode. It is up to the caller to 1328c2ecf20Sopenharmony_ci * initialize the fields of @msg (other than @msg->list) appropriately. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ciint 1358c2ecf20Sopenharmony_cirpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci int res = -EPIPE; 1388c2ecf20Sopenharmony_ci struct dentry *dentry; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci spin_lock(&pipe->lock); 1418c2ecf20Sopenharmony_ci if (pipe->nreaders) { 1428c2ecf20Sopenharmony_ci list_add_tail(&msg->list, &pipe->pipe); 1438c2ecf20Sopenharmony_ci pipe->pipelen += msg->len; 1448c2ecf20Sopenharmony_ci res = 0; 1458c2ecf20Sopenharmony_ci } else if (pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) { 1468c2ecf20Sopenharmony_ci if (list_empty(&pipe->pipe)) 1478c2ecf20Sopenharmony_ci queue_delayed_work(rpciod_workqueue, 1488c2ecf20Sopenharmony_ci &pipe->queue_timeout, 1498c2ecf20Sopenharmony_ci RPC_UPCALL_TIMEOUT); 1508c2ecf20Sopenharmony_ci list_add_tail(&msg->list, &pipe->pipe); 1518c2ecf20Sopenharmony_ci pipe->pipelen += msg->len; 1528c2ecf20Sopenharmony_ci res = 0; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci dentry = dget(pipe->dentry); 1558c2ecf20Sopenharmony_ci spin_unlock(&pipe->lock); 1568c2ecf20Sopenharmony_ci if (dentry) { 1578c2ecf20Sopenharmony_ci wake_up(&RPC_I(d_inode(dentry))->waitq); 1588c2ecf20Sopenharmony_ci dput(dentry); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci return res; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_queue_upcall); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic inline void 1658c2ecf20Sopenharmony_cirpc_inode_setowner(struct inode *inode, void *private) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci RPC_I(inode)->private = private; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic void 1718c2ecf20Sopenharmony_cirpc_close_pipes(struct inode *inode) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct rpc_pipe *pipe = RPC_I(inode)->pipe; 1748c2ecf20Sopenharmony_ci int need_release; 1758c2ecf20Sopenharmony_ci LIST_HEAD(free_list); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci inode_lock(inode); 1788c2ecf20Sopenharmony_ci spin_lock(&pipe->lock); 1798c2ecf20Sopenharmony_ci need_release = pipe->nreaders != 0 || pipe->nwriters != 0; 1808c2ecf20Sopenharmony_ci pipe->nreaders = 0; 1818c2ecf20Sopenharmony_ci list_splice_init(&pipe->in_upcall, &free_list); 1828c2ecf20Sopenharmony_ci list_splice_init(&pipe->pipe, &free_list); 1838c2ecf20Sopenharmony_ci pipe->pipelen = 0; 1848c2ecf20Sopenharmony_ci pipe->dentry = NULL; 1858c2ecf20Sopenharmony_ci spin_unlock(&pipe->lock); 1868c2ecf20Sopenharmony_ci rpc_purge_list(&RPC_I(inode)->waitq, &free_list, pipe->ops->destroy_msg, -EPIPE); 1878c2ecf20Sopenharmony_ci pipe->nwriters = 0; 1888c2ecf20Sopenharmony_ci if (need_release && pipe->ops->release_pipe) 1898c2ecf20Sopenharmony_ci pipe->ops->release_pipe(inode); 1908c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&pipe->queue_timeout); 1918c2ecf20Sopenharmony_ci rpc_inode_setowner(inode, NULL); 1928c2ecf20Sopenharmony_ci RPC_I(inode)->pipe = NULL; 1938c2ecf20Sopenharmony_ci inode_unlock(inode); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic struct inode * 1978c2ecf20Sopenharmony_cirpc_alloc_inode(struct super_block *sb) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct rpc_inode *rpci; 2008c2ecf20Sopenharmony_ci rpci = kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); 2018c2ecf20Sopenharmony_ci if (!rpci) 2028c2ecf20Sopenharmony_ci return NULL; 2038c2ecf20Sopenharmony_ci return &rpci->vfs_inode; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic void 2078c2ecf20Sopenharmony_cirpc_free_inode(struct inode *inode) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci kmem_cache_free(rpc_inode_cachep, RPC_I(inode)); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int 2138c2ecf20Sopenharmony_cirpc_pipe_open(struct inode *inode, struct file *filp) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct rpc_pipe *pipe; 2168c2ecf20Sopenharmony_ci int first_open; 2178c2ecf20Sopenharmony_ci int res = -ENXIO; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci inode_lock(inode); 2208c2ecf20Sopenharmony_ci pipe = RPC_I(inode)->pipe; 2218c2ecf20Sopenharmony_ci if (pipe == NULL) 2228c2ecf20Sopenharmony_ci goto out; 2238c2ecf20Sopenharmony_ci first_open = pipe->nreaders == 0 && pipe->nwriters == 0; 2248c2ecf20Sopenharmony_ci if (first_open && pipe->ops->open_pipe) { 2258c2ecf20Sopenharmony_ci res = pipe->ops->open_pipe(inode); 2268c2ecf20Sopenharmony_ci if (res) 2278c2ecf20Sopenharmony_ci goto out; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci if (filp->f_mode & FMODE_READ) 2308c2ecf20Sopenharmony_ci pipe->nreaders++; 2318c2ecf20Sopenharmony_ci if (filp->f_mode & FMODE_WRITE) 2328c2ecf20Sopenharmony_ci pipe->nwriters++; 2338c2ecf20Sopenharmony_ci res = 0; 2348c2ecf20Sopenharmony_ciout: 2358c2ecf20Sopenharmony_ci inode_unlock(inode); 2368c2ecf20Sopenharmony_ci return res; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic int 2408c2ecf20Sopenharmony_cirpc_pipe_release(struct inode *inode, struct file *filp) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct rpc_pipe *pipe; 2438c2ecf20Sopenharmony_ci struct rpc_pipe_msg *msg; 2448c2ecf20Sopenharmony_ci int last_close; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci inode_lock(inode); 2478c2ecf20Sopenharmony_ci pipe = RPC_I(inode)->pipe; 2488c2ecf20Sopenharmony_ci if (pipe == NULL) 2498c2ecf20Sopenharmony_ci goto out; 2508c2ecf20Sopenharmony_ci msg = filp->private_data; 2518c2ecf20Sopenharmony_ci if (msg != NULL) { 2528c2ecf20Sopenharmony_ci spin_lock(&pipe->lock); 2538c2ecf20Sopenharmony_ci msg->errno = -EAGAIN; 2548c2ecf20Sopenharmony_ci list_del_init(&msg->list); 2558c2ecf20Sopenharmony_ci spin_unlock(&pipe->lock); 2568c2ecf20Sopenharmony_ci pipe->ops->destroy_msg(msg); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci if (filp->f_mode & FMODE_WRITE) 2598c2ecf20Sopenharmony_ci pipe->nwriters --; 2608c2ecf20Sopenharmony_ci if (filp->f_mode & FMODE_READ) { 2618c2ecf20Sopenharmony_ci pipe->nreaders --; 2628c2ecf20Sopenharmony_ci if (pipe->nreaders == 0) { 2638c2ecf20Sopenharmony_ci LIST_HEAD(free_list); 2648c2ecf20Sopenharmony_ci spin_lock(&pipe->lock); 2658c2ecf20Sopenharmony_ci list_splice_init(&pipe->pipe, &free_list); 2668c2ecf20Sopenharmony_ci pipe->pipelen = 0; 2678c2ecf20Sopenharmony_ci spin_unlock(&pipe->lock); 2688c2ecf20Sopenharmony_ci rpc_purge_list(&RPC_I(inode)->waitq, &free_list, 2698c2ecf20Sopenharmony_ci pipe->ops->destroy_msg, -EAGAIN); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci last_close = pipe->nwriters == 0 && pipe->nreaders == 0; 2738c2ecf20Sopenharmony_ci if (last_close && pipe->ops->release_pipe) 2748c2ecf20Sopenharmony_ci pipe->ops->release_pipe(inode); 2758c2ecf20Sopenharmony_ciout: 2768c2ecf20Sopenharmony_ci inode_unlock(inode); 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic ssize_t 2818c2ecf20Sopenharmony_cirpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct inode *inode = file_inode(filp); 2848c2ecf20Sopenharmony_ci struct rpc_pipe *pipe; 2858c2ecf20Sopenharmony_ci struct rpc_pipe_msg *msg; 2868c2ecf20Sopenharmony_ci int res = 0; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci inode_lock(inode); 2898c2ecf20Sopenharmony_ci pipe = RPC_I(inode)->pipe; 2908c2ecf20Sopenharmony_ci if (pipe == NULL) { 2918c2ecf20Sopenharmony_ci res = -EPIPE; 2928c2ecf20Sopenharmony_ci goto out_unlock; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci msg = filp->private_data; 2958c2ecf20Sopenharmony_ci if (msg == NULL) { 2968c2ecf20Sopenharmony_ci spin_lock(&pipe->lock); 2978c2ecf20Sopenharmony_ci if (!list_empty(&pipe->pipe)) { 2988c2ecf20Sopenharmony_ci msg = list_entry(pipe->pipe.next, 2998c2ecf20Sopenharmony_ci struct rpc_pipe_msg, 3008c2ecf20Sopenharmony_ci list); 3018c2ecf20Sopenharmony_ci list_move(&msg->list, &pipe->in_upcall); 3028c2ecf20Sopenharmony_ci pipe->pipelen -= msg->len; 3038c2ecf20Sopenharmony_ci filp->private_data = msg; 3048c2ecf20Sopenharmony_ci msg->copied = 0; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci spin_unlock(&pipe->lock); 3078c2ecf20Sopenharmony_ci if (msg == NULL) 3088c2ecf20Sopenharmony_ci goto out_unlock; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci /* NOTE: it is up to the callback to update msg->copied */ 3118c2ecf20Sopenharmony_ci res = pipe->ops->upcall(filp, msg, buf, len); 3128c2ecf20Sopenharmony_ci if (res < 0 || msg->len == msg->copied) { 3138c2ecf20Sopenharmony_ci filp->private_data = NULL; 3148c2ecf20Sopenharmony_ci spin_lock(&pipe->lock); 3158c2ecf20Sopenharmony_ci list_del_init(&msg->list); 3168c2ecf20Sopenharmony_ci spin_unlock(&pipe->lock); 3178c2ecf20Sopenharmony_ci pipe->ops->destroy_msg(msg); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ciout_unlock: 3208c2ecf20Sopenharmony_ci inode_unlock(inode); 3218c2ecf20Sopenharmony_ci return res; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic ssize_t 3258c2ecf20Sopenharmony_cirpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct inode *inode = file_inode(filp); 3288c2ecf20Sopenharmony_ci int res; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci inode_lock(inode); 3318c2ecf20Sopenharmony_ci res = -EPIPE; 3328c2ecf20Sopenharmony_ci if (RPC_I(inode)->pipe != NULL) 3338c2ecf20Sopenharmony_ci res = RPC_I(inode)->pipe->ops->downcall(filp, buf, len); 3348c2ecf20Sopenharmony_ci inode_unlock(inode); 3358c2ecf20Sopenharmony_ci return res; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic __poll_t 3398c2ecf20Sopenharmony_cirpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct inode *inode = file_inode(filp); 3428c2ecf20Sopenharmony_ci struct rpc_inode *rpci = RPC_I(inode); 3438c2ecf20Sopenharmony_ci __poll_t mask = EPOLLOUT | EPOLLWRNORM; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci poll_wait(filp, &rpci->waitq, wait); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci inode_lock(inode); 3488c2ecf20Sopenharmony_ci if (rpci->pipe == NULL) 3498c2ecf20Sopenharmony_ci mask |= EPOLLERR | EPOLLHUP; 3508c2ecf20Sopenharmony_ci else if (filp->private_data || !list_empty(&rpci->pipe->pipe)) 3518c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 3528c2ecf20Sopenharmony_ci inode_unlock(inode); 3538c2ecf20Sopenharmony_ci return mask; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic long 3578c2ecf20Sopenharmony_cirpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct inode *inode = file_inode(filp); 3608c2ecf20Sopenharmony_ci struct rpc_pipe *pipe; 3618c2ecf20Sopenharmony_ci int len; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci switch (cmd) { 3648c2ecf20Sopenharmony_ci case FIONREAD: 3658c2ecf20Sopenharmony_ci inode_lock(inode); 3668c2ecf20Sopenharmony_ci pipe = RPC_I(inode)->pipe; 3678c2ecf20Sopenharmony_ci if (pipe == NULL) { 3688c2ecf20Sopenharmony_ci inode_unlock(inode); 3698c2ecf20Sopenharmony_ci return -EPIPE; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci spin_lock(&pipe->lock); 3728c2ecf20Sopenharmony_ci len = pipe->pipelen; 3738c2ecf20Sopenharmony_ci if (filp->private_data) { 3748c2ecf20Sopenharmony_ci struct rpc_pipe_msg *msg; 3758c2ecf20Sopenharmony_ci msg = filp->private_data; 3768c2ecf20Sopenharmony_ci len += msg->len - msg->copied; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci spin_unlock(&pipe->lock); 3798c2ecf20Sopenharmony_ci inode_unlock(inode); 3808c2ecf20Sopenharmony_ci return put_user(len, (int __user *)arg); 3818c2ecf20Sopenharmony_ci default: 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic const struct file_operations rpc_pipe_fops = { 3878c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3888c2ecf20Sopenharmony_ci .llseek = no_llseek, 3898c2ecf20Sopenharmony_ci .read = rpc_pipe_read, 3908c2ecf20Sopenharmony_ci .write = rpc_pipe_write, 3918c2ecf20Sopenharmony_ci .poll = rpc_pipe_poll, 3928c2ecf20Sopenharmony_ci .unlocked_ioctl = rpc_pipe_ioctl, 3938c2ecf20Sopenharmony_ci .open = rpc_pipe_open, 3948c2ecf20Sopenharmony_ci .release = rpc_pipe_release, 3958c2ecf20Sopenharmony_ci}; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int 3988c2ecf20Sopenharmony_cirpc_show_info(struct seq_file *m, void *v) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct rpc_clnt *clnt = m->private; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci rcu_read_lock(); 4038c2ecf20Sopenharmony_ci seq_printf(m, "RPC server: %s\n", 4048c2ecf20Sopenharmony_ci rcu_dereference(clnt->cl_xprt)->servername); 4058c2ecf20Sopenharmony_ci seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_program->name, 4068c2ecf20Sopenharmony_ci clnt->cl_prog, clnt->cl_vers); 4078c2ecf20Sopenharmony_ci seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); 4088c2ecf20Sopenharmony_ci seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); 4098c2ecf20Sopenharmony_ci seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); 4108c2ecf20Sopenharmony_ci rcu_read_unlock(); 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int 4158c2ecf20Sopenharmony_cirpc_info_open(struct inode *inode, struct file *file) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct rpc_clnt *clnt = NULL; 4188c2ecf20Sopenharmony_ci int ret = single_open(file, rpc_show_info, NULL); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (!ret) { 4218c2ecf20Sopenharmony_ci struct seq_file *m = file->private_data; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci spin_lock(&file->f_path.dentry->d_lock); 4248c2ecf20Sopenharmony_ci if (!d_unhashed(file->f_path.dentry)) 4258c2ecf20Sopenharmony_ci clnt = RPC_I(inode)->private; 4268c2ecf20Sopenharmony_ci if (clnt != NULL && atomic_inc_not_zero(&clnt->cl_count)) { 4278c2ecf20Sopenharmony_ci spin_unlock(&file->f_path.dentry->d_lock); 4288c2ecf20Sopenharmony_ci m->private = clnt; 4298c2ecf20Sopenharmony_ci } else { 4308c2ecf20Sopenharmony_ci spin_unlock(&file->f_path.dentry->d_lock); 4318c2ecf20Sopenharmony_ci single_release(inode, file); 4328c2ecf20Sopenharmony_ci ret = -EINVAL; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci return ret; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic int 4398c2ecf20Sopenharmony_cirpc_info_release(struct inode *inode, struct file *file) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct seq_file *m = file->private_data; 4428c2ecf20Sopenharmony_ci struct rpc_clnt *clnt = (struct rpc_clnt *)m->private; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (clnt) 4458c2ecf20Sopenharmony_ci rpc_release_client(clnt); 4468c2ecf20Sopenharmony_ci return single_release(inode, file); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic const struct file_operations rpc_info_operations = { 4508c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4518c2ecf20Sopenharmony_ci .open = rpc_info_open, 4528c2ecf20Sopenharmony_ci .read = seq_read, 4538c2ecf20Sopenharmony_ci .llseek = seq_lseek, 4548c2ecf20Sopenharmony_ci .release = rpc_info_release, 4558c2ecf20Sopenharmony_ci}; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci/* 4598c2ecf20Sopenharmony_ci * Description of fs contents. 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_cistruct rpc_filelist { 4628c2ecf20Sopenharmony_ci const char *name; 4638c2ecf20Sopenharmony_ci const struct file_operations *i_fop; 4648c2ecf20Sopenharmony_ci umode_t mode; 4658c2ecf20Sopenharmony_ci}; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic struct inode * 4688c2ecf20Sopenharmony_cirpc_get_inode(struct super_block *sb, umode_t mode) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct inode *inode = new_inode(sb); 4718c2ecf20Sopenharmony_ci if (!inode) 4728c2ecf20Sopenharmony_ci return NULL; 4738c2ecf20Sopenharmony_ci inode->i_ino = get_next_ino(); 4748c2ecf20Sopenharmony_ci inode->i_mode = mode; 4758c2ecf20Sopenharmony_ci inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); 4768c2ecf20Sopenharmony_ci switch (mode & S_IFMT) { 4778c2ecf20Sopenharmony_ci case S_IFDIR: 4788c2ecf20Sopenharmony_ci inode->i_fop = &simple_dir_operations; 4798c2ecf20Sopenharmony_ci inode->i_op = &simple_dir_inode_operations; 4808c2ecf20Sopenharmony_ci inc_nlink(inode); 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci default: 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci return inode; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int __rpc_create_common(struct inode *dir, struct dentry *dentry, 4898c2ecf20Sopenharmony_ci umode_t mode, 4908c2ecf20Sopenharmony_ci const struct file_operations *i_fop, 4918c2ecf20Sopenharmony_ci void *private) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci struct inode *inode; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci d_drop(dentry); 4968c2ecf20Sopenharmony_ci inode = rpc_get_inode(dir->i_sb, mode); 4978c2ecf20Sopenharmony_ci if (!inode) 4988c2ecf20Sopenharmony_ci goto out_err; 4998c2ecf20Sopenharmony_ci inode->i_ino = iunique(dir->i_sb, 100); 5008c2ecf20Sopenharmony_ci if (i_fop) 5018c2ecf20Sopenharmony_ci inode->i_fop = i_fop; 5028c2ecf20Sopenharmony_ci if (private) 5038c2ecf20Sopenharmony_ci rpc_inode_setowner(inode, private); 5048c2ecf20Sopenharmony_ci d_add(dentry, inode); 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ciout_err: 5078c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %pd\n", 5088c2ecf20Sopenharmony_ci __FILE__, __func__, dentry); 5098c2ecf20Sopenharmony_ci dput(dentry); 5108c2ecf20Sopenharmony_ci return -ENOMEM; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int __rpc_create(struct inode *dir, struct dentry *dentry, 5148c2ecf20Sopenharmony_ci umode_t mode, 5158c2ecf20Sopenharmony_ci const struct file_operations *i_fop, 5168c2ecf20Sopenharmony_ci void *private) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci int err; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private); 5218c2ecf20Sopenharmony_ci if (err) 5228c2ecf20Sopenharmony_ci return err; 5238c2ecf20Sopenharmony_ci fsnotify_create(dir, dentry); 5248c2ecf20Sopenharmony_ci return 0; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic int __rpc_mkdir(struct inode *dir, struct dentry *dentry, 5288c2ecf20Sopenharmony_ci umode_t mode, 5298c2ecf20Sopenharmony_ci const struct file_operations *i_fop, 5308c2ecf20Sopenharmony_ci void *private) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci int err; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private); 5358c2ecf20Sopenharmony_ci if (err) 5368c2ecf20Sopenharmony_ci return err; 5378c2ecf20Sopenharmony_ci inc_nlink(dir); 5388c2ecf20Sopenharmony_ci fsnotify_mkdir(dir, dentry); 5398c2ecf20Sopenharmony_ci return 0; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic void 5438c2ecf20Sopenharmony_ciinit_pipe(struct rpc_pipe *pipe) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci pipe->nreaders = 0; 5468c2ecf20Sopenharmony_ci pipe->nwriters = 0; 5478c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pipe->in_upcall); 5488c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pipe->in_downcall); 5498c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pipe->pipe); 5508c2ecf20Sopenharmony_ci pipe->pipelen = 0; 5518c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&pipe->queue_timeout, 5528c2ecf20Sopenharmony_ci rpc_timeout_upcall_queue); 5538c2ecf20Sopenharmony_ci pipe->ops = NULL; 5548c2ecf20Sopenharmony_ci spin_lock_init(&pipe->lock); 5558c2ecf20Sopenharmony_ci pipe->dentry = NULL; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_civoid rpc_destroy_pipe_data(struct rpc_pipe *pipe) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci kfree(pipe); 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_destroy_pipe_data); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistruct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci struct rpc_pipe *pipe; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci pipe = kzalloc(sizeof(struct rpc_pipe), GFP_KERNEL); 5698c2ecf20Sopenharmony_ci if (!pipe) 5708c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 5718c2ecf20Sopenharmony_ci init_pipe(pipe); 5728c2ecf20Sopenharmony_ci pipe->ops = ops; 5738c2ecf20Sopenharmony_ci pipe->flags = flags; 5748c2ecf20Sopenharmony_ci return pipe; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_mkpipe_data); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry, 5798c2ecf20Sopenharmony_ci umode_t mode, 5808c2ecf20Sopenharmony_ci const struct file_operations *i_fop, 5818c2ecf20Sopenharmony_ci void *private, 5828c2ecf20Sopenharmony_ci struct rpc_pipe *pipe) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct rpc_inode *rpci; 5858c2ecf20Sopenharmony_ci int err; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private); 5888c2ecf20Sopenharmony_ci if (err) 5898c2ecf20Sopenharmony_ci return err; 5908c2ecf20Sopenharmony_ci rpci = RPC_I(d_inode(dentry)); 5918c2ecf20Sopenharmony_ci rpci->private = private; 5928c2ecf20Sopenharmony_ci rpci->pipe = pipe; 5938c2ecf20Sopenharmony_ci fsnotify_create(dir, dentry); 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int __rpc_rmdir(struct inode *dir, struct dentry *dentry) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci int ret; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci dget(dentry); 6028c2ecf20Sopenharmony_ci ret = simple_rmdir(dir, dentry); 6038c2ecf20Sopenharmony_ci d_drop(dentry); 6048c2ecf20Sopenharmony_ci if (!ret) 6058c2ecf20Sopenharmony_ci fsnotify_rmdir(dir, dentry); 6068c2ecf20Sopenharmony_ci dput(dentry); 6078c2ecf20Sopenharmony_ci return ret; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic int __rpc_unlink(struct inode *dir, struct dentry *dentry) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci int ret; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci dget(dentry); 6158c2ecf20Sopenharmony_ci ret = simple_unlink(dir, dentry); 6168c2ecf20Sopenharmony_ci d_drop(dentry); 6178c2ecf20Sopenharmony_ci if (!ret) 6188c2ecf20Sopenharmony_ci fsnotify_unlink(dir, dentry); 6198c2ecf20Sopenharmony_ci dput(dentry); 6208c2ecf20Sopenharmony_ci return ret; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic int __rpc_rmpipe(struct inode *dir, struct dentry *dentry) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci rpc_close_pipes(inode); 6288c2ecf20Sopenharmony_ci return __rpc_unlink(dir, dentry); 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, 6328c2ecf20Sopenharmony_ci const char *name) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci struct qstr q = QSTR_INIT(name, strlen(name)); 6358c2ecf20Sopenharmony_ci struct dentry *dentry = d_hash_and_lookup(parent, &q); 6368c2ecf20Sopenharmony_ci if (!dentry) { 6378c2ecf20Sopenharmony_ci dentry = d_alloc(parent, &q); 6388c2ecf20Sopenharmony_ci if (!dentry) 6398c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci if (d_really_is_negative(dentry)) 6428c2ecf20Sopenharmony_ci return dentry; 6438c2ecf20Sopenharmony_ci dput(dentry); 6448c2ecf20Sopenharmony_ci return ERR_PTR(-EEXIST); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci/* 6488c2ecf20Sopenharmony_ci * FIXME: This probably has races. 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_cistatic void __rpc_depopulate(struct dentry *parent, 6518c2ecf20Sopenharmony_ci const struct rpc_filelist *files, 6528c2ecf20Sopenharmony_ci int start, int eof) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct inode *dir = d_inode(parent); 6558c2ecf20Sopenharmony_ci struct dentry *dentry; 6568c2ecf20Sopenharmony_ci struct qstr name; 6578c2ecf20Sopenharmony_ci int i; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci for (i = start; i < eof; i++) { 6608c2ecf20Sopenharmony_ci name.name = files[i].name; 6618c2ecf20Sopenharmony_ci name.len = strlen(files[i].name); 6628c2ecf20Sopenharmony_ci dentry = d_hash_and_lookup(parent, &name); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (dentry == NULL) 6658c2ecf20Sopenharmony_ci continue; 6668c2ecf20Sopenharmony_ci if (d_really_is_negative(dentry)) 6678c2ecf20Sopenharmony_ci goto next; 6688c2ecf20Sopenharmony_ci switch (d_inode(dentry)->i_mode & S_IFMT) { 6698c2ecf20Sopenharmony_ci default: 6708c2ecf20Sopenharmony_ci BUG(); 6718c2ecf20Sopenharmony_ci case S_IFREG: 6728c2ecf20Sopenharmony_ci __rpc_unlink(dir, dentry); 6738c2ecf20Sopenharmony_ci break; 6748c2ecf20Sopenharmony_ci case S_IFDIR: 6758c2ecf20Sopenharmony_ci __rpc_rmdir(dir, dentry); 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_cinext: 6788c2ecf20Sopenharmony_ci dput(dentry); 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic void rpc_depopulate(struct dentry *parent, 6838c2ecf20Sopenharmony_ci const struct rpc_filelist *files, 6848c2ecf20Sopenharmony_ci int start, int eof) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct inode *dir = d_inode(parent); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci inode_lock_nested(dir, I_MUTEX_CHILD); 6898c2ecf20Sopenharmony_ci __rpc_depopulate(parent, files, start, eof); 6908c2ecf20Sopenharmony_ci inode_unlock(dir); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic int rpc_populate(struct dentry *parent, 6948c2ecf20Sopenharmony_ci const struct rpc_filelist *files, 6958c2ecf20Sopenharmony_ci int start, int eof, 6968c2ecf20Sopenharmony_ci void *private) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci struct inode *dir = d_inode(parent); 6998c2ecf20Sopenharmony_ci struct dentry *dentry; 7008c2ecf20Sopenharmony_ci int i, err; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci inode_lock(dir); 7038c2ecf20Sopenharmony_ci for (i = start; i < eof; i++) { 7048c2ecf20Sopenharmony_ci dentry = __rpc_lookup_create_exclusive(parent, files[i].name); 7058c2ecf20Sopenharmony_ci err = PTR_ERR(dentry); 7068c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) 7078c2ecf20Sopenharmony_ci goto out_bad; 7088c2ecf20Sopenharmony_ci switch (files[i].mode & S_IFMT) { 7098c2ecf20Sopenharmony_ci default: 7108c2ecf20Sopenharmony_ci BUG(); 7118c2ecf20Sopenharmony_ci case S_IFREG: 7128c2ecf20Sopenharmony_ci err = __rpc_create(dir, dentry, 7138c2ecf20Sopenharmony_ci files[i].mode, 7148c2ecf20Sopenharmony_ci files[i].i_fop, 7158c2ecf20Sopenharmony_ci private); 7168c2ecf20Sopenharmony_ci break; 7178c2ecf20Sopenharmony_ci case S_IFDIR: 7188c2ecf20Sopenharmony_ci err = __rpc_mkdir(dir, dentry, 7198c2ecf20Sopenharmony_ci files[i].mode, 7208c2ecf20Sopenharmony_ci NULL, 7218c2ecf20Sopenharmony_ci private); 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci if (err != 0) 7248c2ecf20Sopenharmony_ci goto out_bad; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci inode_unlock(dir); 7278c2ecf20Sopenharmony_ci return 0; 7288c2ecf20Sopenharmony_ciout_bad: 7298c2ecf20Sopenharmony_ci __rpc_depopulate(parent, files, start, eof); 7308c2ecf20Sopenharmony_ci inode_unlock(dir); 7318c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: %s failed to populate directory %pd\n", 7328c2ecf20Sopenharmony_ci __FILE__, __func__, parent); 7338c2ecf20Sopenharmony_ci return err; 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic struct dentry *rpc_mkdir_populate(struct dentry *parent, 7378c2ecf20Sopenharmony_ci const char *name, umode_t mode, void *private, 7388c2ecf20Sopenharmony_ci int (*populate)(struct dentry *, void *), void *args_populate) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci struct dentry *dentry; 7418c2ecf20Sopenharmony_ci struct inode *dir = d_inode(parent); 7428c2ecf20Sopenharmony_ci int error; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci inode_lock_nested(dir, I_MUTEX_PARENT); 7458c2ecf20Sopenharmony_ci dentry = __rpc_lookup_create_exclusive(parent, name); 7468c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) 7478c2ecf20Sopenharmony_ci goto out; 7488c2ecf20Sopenharmony_ci error = __rpc_mkdir(dir, dentry, mode, NULL, private); 7498c2ecf20Sopenharmony_ci if (error != 0) 7508c2ecf20Sopenharmony_ci goto out_err; 7518c2ecf20Sopenharmony_ci if (populate != NULL) { 7528c2ecf20Sopenharmony_ci error = populate(dentry, args_populate); 7538c2ecf20Sopenharmony_ci if (error) 7548c2ecf20Sopenharmony_ci goto err_rmdir; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ciout: 7578c2ecf20Sopenharmony_ci inode_unlock(dir); 7588c2ecf20Sopenharmony_ci return dentry; 7598c2ecf20Sopenharmony_cierr_rmdir: 7608c2ecf20Sopenharmony_ci __rpc_rmdir(dir, dentry); 7618c2ecf20Sopenharmony_ciout_err: 7628c2ecf20Sopenharmony_ci dentry = ERR_PTR(error); 7638c2ecf20Sopenharmony_ci goto out; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic int rpc_rmdir_depopulate(struct dentry *dentry, 7678c2ecf20Sopenharmony_ci void (*depopulate)(struct dentry *)) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct dentry *parent; 7708c2ecf20Sopenharmony_ci struct inode *dir; 7718c2ecf20Sopenharmony_ci int error; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci parent = dget_parent(dentry); 7748c2ecf20Sopenharmony_ci dir = d_inode(parent); 7758c2ecf20Sopenharmony_ci inode_lock_nested(dir, I_MUTEX_PARENT); 7768c2ecf20Sopenharmony_ci if (depopulate != NULL) 7778c2ecf20Sopenharmony_ci depopulate(dentry); 7788c2ecf20Sopenharmony_ci error = __rpc_rmdir(dir, dentry); 7798c2ecf20Sopenharmony_ci inode_unlock(dir); 7808c2ecf20Sopenharmony_ci dput(parent); 7818c2ecf20Sopenharmony_ci return error; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci/** 7858c2ecf20Sopenharmony_ci * rpc_mkpipe - make an rpc_pipefs file for kernel<->userspace communication 7868c2ecf20Sopenharmony_ci * @parent: dentry of directory to create new "pipe" in 7878c2ecf20Sopenharmony_ci * @name: name of pipe 7888c2ecf20Sopenharmony_ci * @private: private data to associate with the pipe, for the caller's use 7898c2ecf20Sopenharmony_ci * @pipe: &rpc_pipe containing input parameters 7908c2ecf20Sopenharmony_ci * 7918c2ecf20Sopenharmony_ci * Data is made available for userspace to read by calls to 7928c2ecf20Sopenharmony_ci * rpc_queue_upcall(). The actual reads will result in calls to 7938c2ecf20Sopenharmony_ci * @ops->upcall, which will be called with the file pointer, 7948c2ecf20Sopenharmony_ci * message, and userspace buffer to copy to. 7958c2ecf20Sopenharmony_ci * 7968c2ecf20Sopenharmony_ci * Writes can come at any time, and do not necessarily have to be 7978c2ecf20Sopenharmony_ci * responses to upcalls. They will result in calls to @msg->downcall. 7988c2ecf20Sopenharmony_ci * 7998c2ecf20Sopenharmony_ci * The @private argument passed here will be available to all these methods 8008c2ecf20Sopenharmony_ci * from the file pointer, via RPC_I(file_inode(file))->private. 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_cistruct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name, 8038c2ecf20Sopenharmony_ci void *private, struct rpc_pipe *pipe) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci struct dentry *dentry; 8068c2ecf20Sopenharmony_ci struct inode *dir = d_inode(parent); 8078c2ecf20Sopenharmony_ci umode_t umode = S_IFIFO | 0600; 8088c2ecf20Sopenharmony_ci int err; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (pipe->ops->upcall == NULL) 8118c2ecf20Sopenharmony_ci umode &= ~0444; 8128c2ecf20Sopenharmony_ci if (pipe->ops->downcall == NULL) 8138c2ecf20Sopenharmony_ci umode &= ~0222; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci inode_lock_nested(dir, I_MUTEX_PARENT); 8168c2ecf20Sopenharmony_ci dentry = __rpc_lookup_create_exclusive(parent, name); 8178c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) 8188c2ecf20Sopenharmony_ci goto out; 8198c2ecf20Sopenharmony_ci err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops, 8208c2ecf20Sopenharmony_ci private, pipe); 8218c2ecf20Sopenharmony_ci if (err) 8228c2ecf20Sopenharmony_ci goto out_err; 8238c2ecf20Sopenharmony_ciout: 8248c2ecf20Sopenharmony_ci inode_unlock(dir); 8258c2ecf20Sopenharmony_ci return dentry; 8268c2ecf20Sopenharmony_ciout_err: 8278c2ecf20Sopenharmony_ci dentry = ERR_PTR(err); 8288c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: %s() failed to create pipe %pd/%s (errno = %d)\n", 8298c2ecf20Sopenharmony_ci __FILE__, __func__, parent, name, 8308c2ecf20Sopenharmony_ci err); 8318c2ecf20Sopenharmony_ci goto out; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_mkpipe_dentry); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci/** 8368c2ecf20Sopenharmony_ci * rpc_unlink - remove a pipe 8378c2ecf20Sopenharmony_ci * @dentry: dentry for the pipe, as returned from rpc_mkpipe 8388c2ecf20Sopenharmony_ci * 8398c2ecf20Sopenharmony_ci * After this call, lookups will no longer find the pipe, and any 8408c2ecf20Sopenharmony_ci * attempts to read or write using preexisting opens of the pipe will 8418c2ecf20Sopenharmony_ci * return -EPIPE. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ciint 8448c2ecf20Sopenharmony_cirpc_unlink(struct dentry *dentry) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci struct dentry *parent; 8478c2ecf20Sopenharmony_ci struct inode *dir; 8488c2ecf20Sopenharmony_ci int error = 0; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci parent = dget_parent(dentry); 8518c2ecf20Sopenharmony_ci dir = d_inode(parent); 8528c2ecf20Sopenharmony_ci inode_lock_nested(dir, I_MUTEX_PARENT); 8538c2ecf20Sopenharmony_ci error = __rpc_rmpipe(dir, dentry); 8548c2ecf20Sopenharmony_ci inode_unlock(dir); 8558c2ecf20Sopenharmony_ci dput(parent); 8568c2ecf20Sopenharmony_ci return error; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_unlink); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci/** 8618c2ecf20Sopenharmony_ci * rpc_init_pipe_dir_head - initialise a struct rpc_pipe_dir_head 8628c2ecf20Sopenharmony_ci * @pdh: pointer to struct rpc_pipe_dir_head 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_civoid rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pdh->pdh_entries); 8678c2ecf20Sopenharmony_ci pdh->pdh_dentry = NULL; 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_init_pipe_dir_head); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci/** 8728c2ecf20Sopenharmony_ci * rpc_init_pipe_dir_object - initialise a struct rpc_pipe_dir_object 8738c2ecf20Sopenharmony_ci * @pdo: pointer to struct rpc_pipe_dir_object 8748c2ecf20Sopenharmony_ci * @pdo_ops: pointer to const struct rpc_pipe_dir_object_ops 8758c2ecf20Sopenharmony_ci * @pdo_data: pointer to caller-defined data 8768c2ecf20Sopenharmony_ci */ 8778c2ecf20Sopenharmony_civoid rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo, 8788c2ecf20Sopenharmony_ci const struct rpc_pipe_dir_object_ops *pdo_ops, 8798c2ecf20Sopenharmony_ci void *pdo_data) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pdo->pdo_head); 8828c2ecf20Sopenharmony_ci pdo->pdo_ops = pdo_ops; 8838c2ecf20Sopenharmony_ci pdo->pdo_data = pdo_data; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_init_pipe_dir_object); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic int 8888c2ecf20Sopenharmony_cirpc_add_pipe_dir_object_locked(struct net *net, 8898c2ecf20Sopenharmony_ci struct rpc_pipe_dir_head *pdh, 8908c2ecf20Sopenharmony_ci struct rpc_pipe_dir_object *pdo) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci int ret = 0; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci if (pdh->pdh_dentry) 8958c2ecf20Sopenharmony_ci ret = pdo->pdo_ops->create(pdh->pdh_dentry, pdo); 8968c2ecf20Sopenharmony_ci if (ret == 0) 8978c2ecf20Sopenharmony_ci list_add_tail(&pdo->pdo_head, &pdh->pdh_entries); 8988c2ecf20Sopenharmony_ci return ret; 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic void 9028c2ecf20Sopenharmony_cirpc_remove_pipe_dir_object_locked(struct net *net, 9038c2ecf20Sopenharmony_ci struct rpc_pipe_dir_head *pdh, 9048c2ecf20Sopenharmony_ci struct rpc_pipe_dir_object *pdo) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci if (pdh->pdh_dentry) 9078c2ecf20Sopenharmony_ci pdo->pdo_ops->destroy(pdh->pdh_dentry, pdo); 9088c2ecf20Sopenharmony_ci list_del_init(&pdo->pdo_head); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci/** 9128c2ecf20Sopenharmony_ci * rpc_add_pipe_dir_object - associate a rpc_pipe_dir_object to a directory 9138c2ecf20Sopenharmony_ci * @net: pointer to struct net 9148c2ecf20Sopenharmony_ci * @pdh: pointer to struct rpc_pipe_dir_head 9158c2ecf20Sopenharmony_ci * @pdo: pointer to struct rpc_pipe_dir_object 9168c2ecf20Sopenharmony_ci * 9178c2ecf20Sopenharmony_ci */ 9188c2ecf20Sopenharmony_ciint 9198c2ecf20Sopenharmony_cirpc_add_pipe_dir_object(struct net *net, 9208c2ecf20Sopenharmony_ci struct rpc_pipe_dir_head *pdh, 9218c2ecf20Sopenharmony_ci struct rpc_pipe_dir_object *pdo) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci int ret = 0; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (list_empty(&pdo->pdo_head)) { 9268c2ecf20Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci mutex_lock(&sn->pipefs_sb_lock); 9298c2ecf20Sopenharmony_ci ret = rpc_add_pipe_dir_object_locked(net, pdh, pdo); 9308c2ecf20Sopenharmony_ci mutex_unlock(&sn->pipefs_sb_lock); 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci return ret; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_add_pipe_dir_object); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci/** 9378c2ecf20Sopenharmony_ci * rpc_remove_pipe_dir_object - remove a rpc_pipe_dir_object from a directory 9388c2ecf20Sopenharmony_ci * @net: pointer to struct net 9398c2ecf20Sopenharmony_ci * @pdh: pointer to struct rpc_pipe_dir_head 9408c2ecf20Sopenharmony_ci * @pdo: pointer to struct rpc_pipe_dir_object 9418c2ecf20Sopenharmony_ci * 9428c2ecf20Sopenharmony_ci */ 9438c2ecf20Sopenharmony_civoid 9448c2ecf20Sopenharmony_cirpc_remove_pipe_dir_object(struct net *net, 9458c2ecf20Sopenharmony_ci struct rpc_pipe_dir_head *pdh, 9468c2ecf20Sopenharmony_ci struct rpc_pipe_dir_object *pdo) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci if (!list_empty(&pdo->pdo_head)) { 9498c2ecf20Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci mutex_lock(&sn->pipefs_sb_lock); 9528c2ecf20Sopenharmony_ci rpc_remove_pipe_dir_object_locked(net, pdh, pdo); 9538c2ecf20Sopenharmony_ci mutex_unlock(&sn->pipefs_sb_lock); 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_remove_pipe_dir_object); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci/** 9598c2ecf20Sopenharmony_ci * rpc_find_or_alloc_pipe_dir_object 9608c2ecf20Sopenharmony_ci * @net: pointer to struct net 9618c2ecf20Sopenharmony_ci * @pdh: pointer to struct rpc_pipe_dir_head 9628c2ecf20Sopenharmony_ci * @match: match struct rpc_pipe_dir_object to data 9638c2ecf20Sopenharmony_ci * @alloc: allocate a new struct rpc_pipe_dir_object 9648c2ecf20Sopenharmony_ci * @data: user defined data for match() and alloc() 9658c2ecf20Sopenharmony_ci * 9668c2ecf20Sopenharmony_ci */ 9678c2ecf20Sopenharmony_cistruct rpc_pipe_dir_object * 9688c2ecf20Sopenharmony_cirpc_find_or_alloc_pipe_dir_object(struct net *net, 9698c2ecf20Sopenharmony_ci struct rpc_pipe_dir_head *pdh, 9708c2ecf20Sopenharmony_ci int (*match)(struct rpc_pipe_dir_object *, void *), 9718c2ecf20Sopenharmony_ci struct rpc_pipe_dir_object *(*alloc)(void *), 9728c2ecf20Sopenharmony_ci void *data) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 9758c2ecf20Sopenharmony_ci struct rpc_pipe_dir_object *pdo; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci mutex_lock(&sn->pipefs_sb_lock); 9788c2ecf20Sopenharmony_ci list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) { 9798c2ecf20Sopenharmony_ci if (!match(pdo, data)) 9808c2ecf20Sopenharmony_ci continue; 9818c2ecf20Sopenharmony_ci goto out; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci pdo = alloc(data); 9848c2ecf20Sopenharmony_ci if (!pdo) 9858c2ecf20Sopenharmony_ci goto out; 9868c2ecf20Sopenharmony_ci rpc_add_pipe_dir_object_locked(net, pdh, pdo); 9878c2ecf20Sopenharmony_ciout: 9888c2ecf20Sopenharmony_ci mutex_unlock(&sn->pipefs_sb_lock); 9898c2ecf20Sopenharmony_ci return pdo; 9908c2ecf20Sopenharmony_ci} 9918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_find_or_alloc_pipe_dir_object); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic void 9948c2ecf20Sopenharmony_cirpc_create_pipe_dir_objects(struct rpc_pipe_dir_head *pdh) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci struct rpc_pipe_dir_object *pdo; 9978c2ecf20Sopenharmony_ci struct dentry *dir = pdh->pdh_dentry; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) 10008c2ecf20Sopenharmony_ci pdo->pdo_ops->create(dir, pdo); 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic void 10048c2ecf20Sopenharmony_cirpc_destroy_pipe_dir_objects(struct rpc_pipe_dir_head *pdh) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct rpc_pipe_dir_object *pdo; 10078c2ecf20Sopenharmony_ci struct dentry *dir = pdh->pdh_dentry; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) 10108c2ecf20Sopenharmony_ci pdo->pdo_ops->destroy(dir, pdo); 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cienum { 10148c2ecf20Sopenharmony_ci RPCAUTH_info, 10158c2ecf20Sopenharmony_ci RPCAUTH_EOF 10168c2ecf20Sopenharmony_ci}; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic const struct rpc_filelist authfiles[] = { 10198c2ecf20Sopenharmony_ci [RPCAUTH_info] = { 10208c2ecf20Sopenharmony_ci .name = "info", 10218c2ecf20Sopenharmony_ci .i_fop = &rpc_info_operations, 10228c2ecf20Sopenharmony_ci .mode = S_IFREG | 0400, 10238c2ecf20Sopenharmony_ci }, 10248c2ecf20Sopenharmony_ci}; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cistatic int rpc_clntdir_populate(struct dentry *dentry, void *private) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci return rpc_populate(dentry, 10298c2ecf20Sopenharmony_ci authfiles, RPCAUTH_info, RPCAUTH_EOF, 10308c2ecf20Sopenharmony_ci private); 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic void rpc_clntdir_depopulate(struct dentry *dentry) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF); 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci/** 10398c2ecf20Sopenharmony_ci * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs 10408c2ecf20Sopenharmony_ci * @dentry: the parent of new directory 10418c2ecf20Sopenharmony_ci * @name: the name of new directory 10428c2ecf20Sopenharmony_ci * @rpc_client: rpc client to associate with this directory 10438c2ecf20Sopenharmony_ci * 10448c2ecf20Sopenharmony_ci * This creates a directory at the given @path associated with 10458c2ecf20Sopenharmony_ci * @rpc_clnt, which will contain a file named "info" with some basic 10468c2ecf20Sopenharmony_ci * information about the client, together with any "pipes" that may 10478c2ecf20Sopenharmony_ci * later be created using rpc_mkpipe(). 10488c2ecf20Sopenharmony_ci */ 10498c2ecf20Sopenharmony_cistruct dentry *rpc_create_client_dir(struct dentry *dentry, 10508c2ecf20Sopenharmony_ci const char *name, 10518c2ecf20Sopenharmony_ci struct rpc_clnt *rpc_client) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci struct dentry *ret; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci ret = rpc_mkdir_populate(dentry, name, 0555, NULL, 10568c2ecf20Sopenharmony_ci rpc_clntdir_populate, rpc_client); 10578c2ecf20Sopenharmony_ci if (!IS_ERR(ret)) { 10588c2ecf20Sopenharmony_ci rpc_client->cl_pipedir_objects.pdh_dentry = ret; 10598c2ecf20Sopenharmony_ci rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects); 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci return ret; 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci/** 10658c2ecf20Sopenharmony_ci * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() 10668c2ecf20Sopenharmony_ci * @rpc_client: rpc_client for the pipe 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_ciint rpc_remove_client_dir(struct rpc_clnt *rpc_client) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci struct dentry *dentry = rpc_client->cl_pipedir_objects.pdh_dentry; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (dentry == NULL) 10738c2ecf20Sopenharmony_ci return 0; 10748c2ecf20Sopenharmony_ci rpc_destroy_pipe_dir_objects(&rpc_client->cl_pipedir_objects); 10758c2ecf20Sopenharmony_ci rpc_client->cl_pipedir_objects.pdh_dentry = NULL; 10768c2ecf20Sopenharmony_ci return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate); 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cistatic const struct rpc_filelist cache_pipefs_files[3] = { 10808c2ecf20Sopenharmony_ci [0] = { 10818c2ecf20Sopenharmony_ci .name = "channel", 10828c2ecf20Sopenharmony_ci .i_fop = &cache_file_operations_pipefs, 10838c2ecf20Sopenharmony_ci .mode = S_IFREG | 0600, 10848c2ecf20Sopenharmony_ci }, 10858c2ecf20Sopenharmony_ci [1] = { 10868c2ecf20Sopenharmony_ci .name = "content", 10878c2ecf20Sopenharmony_ci .i_fop = &content_file_operations_pipefs, 10888c2ecf20Sopenharmony_ci .mode = S_IFREG | 0400, 10898c2ecf20Sopenharmony_ci }, 10908c2ecf20Sopenharmony_ci [2] = { 10918c2ecf20Sopenharmony_ci .name = "flush", 10928c2ecf20Sopenharmony_ci .i_fop = &cache_flush_operations_pipefs, 10938c2ecf20Sopenharmony_ci .mode = S_IFREG | 0600, 10948c2ecf20Sopenharmony_ci }, 10958c2ecf20Sopenharmony_ci}; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic int rpc_cachedir_populate(struct dentry *dentry, void *private) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci return rpc_populate(dentry, 11008c2ecf20Sopenharmony_ci cache_pipefs_files, 0, 3, 11018c2ecf20Sopenharmony_ci private); 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic void rpc_cachedir_depopulate(struct dentry *dentry) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci rpc_depopulate(dentry, cache_pipefs_files, 0, 3); 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistruct dentry *rpc_create_cache_dir(struct dentry *parent, const char *name, 11108c2ecf20Sopenharmony_ci umode_t umode, struct cache_detail *cd) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci return rpc_mkdir_populate(parent, name, umode, NULL, 11138c2ecf20Sopenharmony_ci rpc_cachedir_populate, cd); 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_civoid rpc_remove_cache_dir(struct dentry *dentry) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate); 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci/* 11228c2ecf20Sopenharmony_ci * populate the filesystem 11238c2ecf20Sopenharmony_ci */ 11248c2ecf20Sopenharmony_cistatic const struct super_operations s_ops = { 11258c2ecf20Sopenharmony_ci .alloc_inode = rpc_alloc_inode, 11268c2ecf20Sopenharmony_ci .free_inode = rpc_free_inode, 11278c2ecf20Sopenharmony_ci .statfs = simple_statfs, 11288c2ecf20Sopenharmony_ci}; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci#define RPCAUTH_GSSMAGIC 0x67596969 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci/* 11338c2ecf20Sopenharmony_ci * We have a single directory with 1 node in it. 11348c2ecf20Sopenharmony_ci */ 11358c2ecf20Sopenharmony_cienum { 11368c2ecf20Sopenharmony_ci RPCAUTH_lockd, 11378c2ecf20Sopenharmony_ci RPCAUTH_mount, 11388c2ecf20Sopenharmony_ci RPCAUTH_nfs, 11398c2ecf20Sopenharmony_ci RPCAUTH_portmap, 11408c2ecf20Sopenharmony_ci RPCAUTH_statd, 11418c2ecf20Sopenharmony_ci RPCAUTH_nfsd4_cb, 11428c2ecf20Sopenharmony_ci RPCAUTH_cache, 11438c2ecf20Sopenharmony_ci RPCAUTH_nfsd, 11448c2ecf20Sopenharmony_ci RPCAUTH_gssd, 11458c2ecf20Sopenharmony_ci RPCAUTH_RootEOF 11468c2ecf20Sopenharmony_ci}; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_cistatic const struct rpc_filelist files[] = { 11498c2ecf20Sopenharmony_ci [RPCAUTH_lockd] = { 11508c2ecf20Sopenharmony_ci .name = "lockd", 11518c2ecf20Sopenharmony_ci .mode = S_IFDIR | 0555, 11528c2ecf20Sopenharmony_ci }, 11538c2ecf20Sopenharmony_ci [RPCAUTH_mount] = { 11548c2ecf20Sopenharmony_ci .name = "mount", 11558c2ecf20Sopenharmony_ci .mode = S_IFDIR | 0555, 11568c2ecf20Sopenharmony_ci }, 11578c2ecf20Sopenharmony_ci [RPCAUTH_nfs] = { 11588c2ecf20Sopenharmony_ci .name = "nfs", 11598c2ecf20Sopenharmony_ci .mode = S_IFDIR | 0555, 11608c2ecf20Sopenharmony_ci }, 11618c2ecf20Sopenharmony_ci [RPCAUTH_portmap] = { 11628c2ecf20Sopenharmony_ci .name = "portmap", 11638c2ecf20Sopenharmony_ci .mode = S_IFDIR | 0555, 11648c2ecf20Sopenharmony_ci }, 11658c2ecf20Sopenharmony_ci [RPCAUTH_statd] = { 11668c2ecf20Sopenharmony_ci .name = "statd", 11678c2ecf20Sopenharmony_ci .mode = S_IFDIR | 0555, 11688c2ecf20Sopenharmony_ci }, 11698c2ecf20Sopenharmony_ci [RPCAUTH_nfsd4_cb] = { 11708c2ecf20Sopenharmony_ci .name = "nfsd4_cb", 11718c2ecf20Sopenharmony_ci .mode = S_IFDIR | 0555, 11728c2ecf20Sopenharmony_ci }, 11738c2ecf20Sopenharmony_ci [RPCAUTH_cache] = { 11748c2ecf20Sopenharmony_ci .name = "cache", 11758c2ecf20Sopenharmony_ci .mode = S_IFDIR | 0555, 11768c2ecf20Sopenharmony_ci }, 11778c2ecf20Sopenharmony_ci [RPCAUTH_nfsd] = { 11788c2ecf20Sopenharmony_ci .name = "nfsd", 11798c2ecf20Sopenharmony_ci .mode = S_IFDIR | 0555, 11808c2ecf20Sopenharmony_ci }, 11818c2ecf20Sopenharmony_ci [RPCAUTH_gssd] = { 11828c2ecf20Sopenharmony_ci .name = "gssd", 11838c2ecf20Sopenharmony_ci .mode = S_IFDIR | 0555, 11848c2ecf20Sopenharmony_ci }, 11858c2ecf20Sopenharmony_ci}; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci/* 11888c2ecf20Sopenharmony_ci * This call can be used only in RPC pipefs mount notification hooks. 11898c2ecf20Sopenharmony_ci */ 11908c2ecf20Sopenharmony_cistruct dentry *rpc_d_lookup_sb(const struct super_block *sb, 11918c2ecf20Sopenharmony_ci const unsigned char *dir_name) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci struct qstr dir = QSTR_INIT(dir_name, strlen(dir_name)); 11948c2ecf20Sopenharmony_ci return d_hash_and_lookup(sb->s_root, &dir); 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_d_lookup_sb); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ciint rpc_pipefs_init_net(struct net *net) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0); 12038c2ecf20Sopenharmony_ci if (IS_ERR(sn->gssd_dummy)) 12048c2ecf20Sopenharmony_ci return PTR_ERR(sn->gssd_dummy); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci mutex_init(&sn->pipefs_sb_lock); 12078c2ecf20Sopenharmony_ci sn->pipe_version = -1; 12088c2ecf20Sopenharmony_ci return 0; 12098c2ecf20Sopenharmony_ci} 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_civoid rpc_pipefs_exit_net(struct net *net) 12128c2ecf20Sopenharmony_ci{ 12138c2ecf20Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci rpc_destroy_pipe_data(sn->gssd_dummy); 12168c2ecf20Sopenharmony_ci} 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci/* 12198c2ecf20Sopenharmony_ci * This call will be used for per network namespace operations calls. 12208c2ecf20Sopenharmony_ci * Note: Function will be returned with pipefs_sb_lock taken if superblock was 12218c2ecf20Sopenharmony_ci * found. This lock have to be released by rpc_put_sb_net() when all operations 12228c2ecf20Sopenharmony_ci * will be completed. 12238c2ecf20Sopenharmony_ci */ 12248c2ecf20Sopenharmony_cistruct super_block *rpc_get_sb_net(const struct net *net) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci mutex_lock(&sn->pipefs_sb_lock); 12298c2ecf20Sopenharmony_ci if (sn->pipefs_sb) 12308c2ecf20Sopenharmony_ci return sn->pipefs_sb; 12318c2ecf20Sopenharmony_ci mutex_unlock(&sn->pipefs_sb_lock); 12328c2ecf20Sopenharmony_ci return NULL; 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_get_sb_net); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_civoid rpc_put_sb_net(const struct net *net) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci WARN_ON(sn->pipefs_sb == NULL); 12418c2ecf20Sopenharmony_ci mutex_unlock(&sn->pipefs_sb_lock); 12428c2ecf20Sopenharmony_ci} 12438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_put_sb_net); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_cistatic const struct rpc_filelist gssd_dummy_clnt_dir[] = { 12468c2ecf20Sopenharmony_ci [0] = { 12478c2ecf20Sopenharmony_ci .name = "clntXX", 12488c2ecf20Sopenharmony_ci .mode = S_IFDIR | 0555, 12498c2ecf20Sopenharmony_ci }, 12508c2ecf20Sopenharmony_ci}; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_cistatic ssize_t 12538c2ecf20Sopenharmony_cidummy_downcall(struct file *filp, const char __user *src, size_t len) 12548c2ecf20Sopenharmony_ci{ 12558c2ecf20Sopenharmony_ci return -EINVAL; 12568c2ecf20Sopenharmony_ci} 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_cistatic const struct rpc_pipe_ops gssd_dummy_pipe_ops = { 12598c2ecf20Sopenharmony_ci .upcall = rpc_pipe_generic_upcall, 12608c2ecf20Sopenharmony_ci .downcall = dummy_downcall, 12618c2ecf20Sopenharmony_ci}; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci/* 12648c2ecf20Sopenharmony_ci * Here we present a bogus "info" file to keep rpc.gssd happy. We don't expect 12658c2ecf20Sopenharmony_ci * that it will ever use this info to handle an upcall, but rpc.gssd expects 12668c2ecf20Sopenharmony_ci * that this file will be there and have a certain format. 12678c2ecf20Sopenharmony_ci */ 12688c2ecf20Sopenharmony_cistatic int 12698c2ecf20Sopenharmony_cirpc_dummy_info_show(struct seq_file *m, void *v) 12708c2ecf20Sopenharmony_ci{ 12718c2ecf20Sopenharmony_ci seq_printf(m, "RPC server: %s\n", utsname()->nodename); 12728c2ecf20Sopenharmony_ci seq_printf(m, "service: foo (1) version 0\n"); 12738c2ecf20Sopenharmony_ci seq_printf(m, "address: 127.0.0.1\n"); 12748c2ecf20Sopenharmony_ci seq_printf(m, "protocol: tcp\n"); 12758c2ecf20Sopenharmony_ci seq_printf(m, "port: 0\n"); 12768c2ecf20Sopenharmony_ci return 0; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(rpc_dummy_info); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic const struct rpc_filelist gssd_dummy_info_file[] = { 12818c2ecf20Sopenharmony_ci [0] = { 12828c2ecf20Sopenharmony_ci .name = "info", 12838c2ecf20Sopenharmony_ci .i_fop = &rpc_dummy_info_fops, 12848c2ecf20Sopenharmony_ci .mode = S_IFREG | 0400, 12858c2ecf20Sopenharmony_ci }, 12868c2ecf20Sopenharmony_ci}; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci/** 12898c2ecf20Sopenharmony_ci * rpc_gssd_dummy_populate - create a dummy gssd pipe 12908c2ecf20Sopenharmony_ci * @root: root of the rpc_pipefs filesystem 12918c2ecf20Sopenharmony_ci * @pipe_data: pipe data created when netns is initialized 12928c2ecf20Sopenharmony_ci * 12938c2ecf20Sopenharmony_ci * Create a dummy set of directories and a pipe that gssd can hold open to 12948c2ecf20Sopenharmony_ci * indicate that it is up and running. 12958c2ecf20Sopenharmony_ci */ 12968c2ecf20Sopenharmony_cistatic struct dentry * 12978c2ecf20Sopenharmony_cirpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci int ret = 0; 13008c2ecf20Sopenharmony_ci struct dentry *gssd_dentry; 13018c2ecf20Sopenharmony_ci struct dentry *clnt_dentry = NULL; 13028c2ecf20Sopenharmony_ci struct dentry *pipe_dentry = NULL; 13038c2ecf20Sopenharmony_ci struct qstr q = QSTR_INIT(files[RPCAUTH_gssd].name, 13048c2ecf20Sopenharmony_ci strlen(files[RPCAUTH_gssd].name)); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci /* We should never get this far if "gssd" doesn't exist */ 13078c2ecf20Sopenharmony_ci gssd_dentry = d_hash_and_lookup(root, &q); 13088c2ecf20Sopenharmony_ci if (!gssd_dentry) 13098c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL); 13128c2ecf20Sopenharmony_ci if (ret) { 13138c2ecf20Sopenharmony_ci pipe_dentry = ERR_PTR(ret); 13148c2ecf20Sopenharmony_ci goto out; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci q.name = gssd_dummy_clnt_dir[0].name; 13188c2ecf20Sopenharmony_ci q.len = strlen(gssd_dummy_clnt_dir[0].name); 13198c2ecf20Sopenharmony_ci clnt_dentry = d_hash_and_lookup(gssd_dentry, &q); 13208c2ecf20Sopenharmony_ci if (!clnt_dentry) { 13218c2ecf20Sopenharmony_ci __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1); 13228c2ecf20Sopenharmony_ci pipe_dentry = ERR_PTR(-ENOENT); 13238c2ecf20Sopenharmony_ci goto out; 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci ret = rpc_populate(clnt_dentry, gssd_dummy_info_file, 0, 1, NULL); 13278c2ecf20Sopenharmony_ci if (ret) { 13288c2ecf20Sopenharmony_ci __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1); 13298c2ecf20Sopenharmony_ci pipe_dentry = ERR_PTR(ret); 13308c2ecf20Sopenharmony_ci goto out; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data); 13348c2ecf20Sopenharmony_ci if (IS_ERR(pipe_dentry)) { 13358c2ecf20Sopenharmony_ci __rpc_depopulate(clnt_dentry, gssd_dummy_info_file, 0, 1); 13368c2ecf20Sopenharmony_ci __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1); 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ciout: 13398c2ecf20Sopenharmony_ci dput(clnt_dentry); 13408c2ecf20Sopenharmony_ci dput(gssd_dentry); 13418c2ecf20Sopenharmony_ci return pipe_dentry; 13428c2ecf20Sopenharmony_ci} 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_cistatic void 13458c2ecf20Sopenharmony_cirpc_gssd_dummy_depopulate(struct dentry *pipe_dentry) 13468c2ecf20Sopenharmony_ci{ 13478c2ecf20Sopenharmony_ci struct dentry *clnt_dir = pipe_dentry->d_parent; 13488c2ecf20Sopenharmony_ci struct dentry *gssd_dir = clnt_dir->d_parent; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci dget(pipe_dentry); 13518c2ecf20Sopenharmony_ci __rpc_rmpipe(d_inode(clnt_dir), pipe_dentry); 13528c2ecf20Sopenharmony_ci __rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1); 13538c2ecf20Sopenharmony_ci __rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1); 13548c2ecf20Sopenharmony_ci dput(pipe_dentry); 13558c2ecf20Sopenharmony_ci} 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_cistatic int 13588c2ecf20Sopenharmony_cirpc_fill_super(struct super_block *sb, struct fs_context *fc) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci struct inode *inode; 13618c2ecf20Sopenharmony_ci struct dentry *root, *gssd_dentry; 13628c2ecf20Sopenharmony_ci struct net *net = sb->s_fs_info; 13638c2ecf20Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 13648c2ecf20Sopenharmony_ci int err; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci sb->s_blocksize = PAGE_SIZE; 13678c2ecf20Sopenharmony_ci sb->s_blocksize_bits = PAGE_SHIFT; 13688c2ecf20Sopenharmony_ci sb->s_magic = RPCAUTH_GSSMAGIC; 13698c2ecf20Sopenharmony_ci sb->s_op = &s_ops; 13708c2ecf20Sopenharmony_ci sb->s_d_op = &simple_dentry_operations; 13718c2ecf20Sopenharmony_ci sb->s_time_gran = 1; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci inode = rpc_get_inode(sb, S_IFDIR | 0555); 13748c2ecf20Sopenharmony_ci sb->s_root = root = d_make_root(inode); 13758c2ecf20Sopenharmony_ci if (!root) 13768c2ecf20Sopenharmony_ci return -ENOMEM; 13778c2ecf20Sopenharmony_ci if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) 13788c2ecf20Sopenharmony_ci return -ENOMEM; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy); 13818c2ecf20Sopenharmony_ci if (IS_ERR(gssd_dentry)) { 13828c2ecf20Sopenharmony_ci __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF); 13838c2ecf20Sopenharmony_ci return PTR_ERR(gssd_dentry); 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci dprintk("RPC: sending pipefs MOUNT notification for net %x%s\n", 13878c2ecf20Sopenharmony_ci net->ns.inum, NET_NAME(net)); 13888c2ecf20Sopenharmony_ci mutex_lock(&sn->pipefs_sb_lock); 13898c2ecf20Sopenharmony_ci sn->pipefs_sb = sb; 13908c2ecf20Sopenharmony_ci err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list, 13918c2ecf20Sopenharmony_ci RPC_PIPEFS_MOUNT, 13928c2ecf20Sopenharmony_ci sb); 13938c2ecf20Sopenharmony_ci if (err) 13948c2ecf20Sopenharmony_ci goto err_depopulate; 13958c2ecf20Sopenharmony_ci mutex_unlock(&sn->pipefs_sb_lock); 13968c2ecf20Sopenharmony_ci return 0; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_cierr_depopulate: 13998c2ecf20Sopenharmony_ci rpc_gssd_dummy_depopulate(gssd_dentry); 14008c2ecf20Sopenharmony_ci blocking_notifier_call_chain(&rpc_pipefs_notifier_list, 14018c2ecf20Sopenharmony_ci RPC_PIPEFS_UMOUNT, 14028c2ecf20Sopenharmony_ci sb); 14038c2ecf20Sopenharmony_ci sn->pipefs_sb = NULL; 14048c2ecf20Sopenharmony_ci __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF); 14058c2ecf20Sopenharmony_ci mutex_unlock(&sn->pipefs_sb_lock); 14068c2ecf20Sopenharmony_ci return err; 14078c2ecf20Sopenharmony_ci} 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_cibool 14108c2ecf20Sopenharmony_cigssd_running(struct net *net) 14118c2ecf20Sopenharmony_ci{ 14128c2ecf20Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 14138c2ecf20Sopenharmony_ci struct rpc_pipe *pipe = sn->gssd_dummy; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci return pipe->nreaders || pipe->nwriters; 14168c2ecf20Sopenharmony_ci} 14178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(gssd_running); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_cistatic int rpc_fs_get_tree(struct fs_context *fc) 14208c2ecf20Sopenharmony_ci{ 14218c2ecf20Sopenharmony_ci return get_tree_keyed(fc, rpc_fill_super, get_net(fc->net_ns)); 14228c2ecf20Sopenharmony_ci} 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_cistatic void rpc_fs_free_fc(struct fs_context *fc) 14258c2ecf20Sopenharmony_ci{ 14268c2ecf20Sopenharmony_ci if (fc->s_fs_info) 14278c2ecf20Sopenharmony_ci put_net(fc->s_fs_info); 14288c2ecf20Sopenharmony_ci} 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_cistatic const struct fs_context_operations rpc_fs_context_ops = { 14318c2ecf20Sopenharmony_ci .free = rpc_fs_free_fc, 14328c2ecf20Sopenharmony_ci .get_tree = rpc_fs_get_tree, 14338c2ecf20Sopenharmony_ci}; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_cistatic int rpc_init_fs_context(struct fs_context *fc) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci put_user_ns(fc->user_ns); 14388c2ecf20Sopenharmony_ci fc->user_ns = get_user_ns(fc->net_ns->user_ns); 14398c2ecf20Sopenharmony_ci fc->ops = &rpc_fs_context_ops; 14408c2ecf20Sopenharmony_ci return 0; 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic void rpc_kill_sb(struct super_block *sb) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci struct net *net = sb->s_fs_info; 14468c2ecf20Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci mutex_lock(&sn->pipefs_sb_lock); 14498c2ecf20Sopenharmony_ci if (sn->pipefs_sb != sb) { 14508c2ecf20Sopenharmony_ci mutex_unlock(&sn->pipefs_sb_lock); 14518c2ecf20Sopenharmony_ci goto out; 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci sn->pipefs_sb = NULL; 14548c2ecf20Sopenharmony_ci dprintk("RPC: sending pipefs UMOUNT notification for net %x%s\n", 14558c2ecf20Sopenharmony_ci net->ns.inum, NET_NAME(net)); 14568c2ecf20Sopenharmony_ci blocking_notifier_call_chain(&rpc_pipefs_notifier_list, 14578c2ecf20Sopenharmony_ci RPC_PIPEFS_UMOUNT, 14588c2ecf20Sopenharmony_ci sb); 14598c2ecf20Sopenharmony_ci mutex_unlock(&sn->pipefs_sb_lock); 14608c2ecf20Sopenharmony_ciout: 14618c2ecf20Sopenharmony_ci kill_litter_super(sb); 14628c2ecf20Sopenharmony_ci put_net(net); 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_cistatic struct file_system_type rpc_pipe_fs_type = { 14668c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 14678c2ecf20Sopenharmony_ci .name = "rpc_pipefs", 14688c2ecf20Sopenharmony_ci .init_fs_context = rpc_init_fs_context, 14698c2ecf20Sopenharmony_ci .kill_sb = rpc_kill_sb, 14708c2ecf20Sopenharmony_ci}; 14718c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("rpc_pipefs"); 14728c2ecf20Sopenharmony_ciMODULE_ALIAS("rpc_pipefs"); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_cistatic void 14758c2ecf20Sopenharmony_ciinit_once(void *foo) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci struct rpc_inode *rpci = (struct rpc_inode *) foo; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci inode_init_once(&rpci->vfs_inode); 14808c2ecf20Sopenharmony_ci rpci->private = NULL; 14818c2ecf20Sopenharmony_ci rpci->pipe = NULL; 14828c2ecf20Sopenharmony_ci init_waitqueue_head(&rpci->waitq); 14838c2ecf20Sopenharmony_ci} 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ciint register_rpc_pipefs(void) 14868c2ecf20Sopenharmony_ci{ 14878c2ecf20Sopenharmony_ci int err; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci rpc_inode_cachep = kmem_cache_create("rpc_inode_cache", 14908c2ecf20Sopenharmony_ci sizeof(struct rpc_inode), 14918c2ecf20Sopenharmony_ci 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| 14928c2ecf20Sopenharmony_ci SLAB_MEM_SPREAD|SLAB_ACCOUNT), 14938c2ecf20Sopenharmony_ci init_once); 14948c2ecf20Sopenharmony_ci if (!rpc_inode_cachep) 14958c2ecf20Sopenharmony_ci return -ENOMEM; 14968c2ecf20Sopenharmony_ci err = rpc_clients_notifier_register(); 14978c2ecf20Sopenharmony_ci if (err) 14988c2ecf20Sopenharmony_ci goto err_notifier; 14998c2ecf20Sopenharmony_ci err = register_filesystem(&rpc_pipe_fs_type); 15008c2ecf20Sopenharmony_ci if (err) 15018c2ecf20Sopenharmony_ci goto err_register; 15028c2ecf20Sopenharmony_ci return 0; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cierr_register: 15058c2ecf20Sopenharmony_ci rpc_clients_notifier_unregister(); 15068c2ecf20Sopenharmony_cierr_notifier: 15078c2ecf20Sopenharmony_ci kmem_cache_destroy(rpc_inode_cachep); 15088c2ecf20Sopenharmony_ci return err; 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_civoid unregister_rpc_pipefs(void) 15128c2ecf20Sopenharmony_ci{ 15138c2ecf20Sopenharmony_ci rpc_clients_notifier_unregister(); 15148c2ecf20Sopenharmony_ci unregister_filesystem(&rpc_pipe_fs_type); 15158c2ecf20Sopenharmony_ci kmem_cache_destroy(rpc_inode_cachep); 15168c2ecf20Sopenharmony_ci} 1517