/** * rpc_queue_upcall - queue an upcall message to userspace * @pipe: upcall pipe on which to queue given message * @msg: message to queue * * Call with an @inode created by rpc_mkpipe() to queue an upcall. * A userspace process may then later read the upcall by performing a * read on an open file for this inode. It is up to the caller to * initialize the fields of @msg (other than @msg->list) appropriately.
*/ int
rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg)
{ int res = -EPIPE; struct dentry *dentry;
spin_lock(&pipe->lock); if (pipe->nreaders) {
list_add_tail(&msg->list, &pipe->pipe);
pipe->pipelen += msg->len;
res = 0;
} elseif (pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) { if (list_empty(&pipe->pipe))
queue_delayed_work(rpciod_workqueue,
&pipe->queue_timeout,
RPC_UPCALL_TIMEOUT);
list_add_tail(&msg->list, &pipe->pipe);
pipe->pipelen += msg->len;
res = 0;
}
dentry = dget(pipe->dentry);
spin_unlock(&pipe->lock); if (dentry) {
wake_up(&RPC_I(d_inode(dentry))->waitq);
dput(dentry);
} return res;
}
EXPORT_SYMBOL_GPL(rpc_queue_upcall);
staticint rpc_populate(struct dentry *parent, conststruct rpc_filelist *files, int start, int eof, void *private)
{ struct dentry *dentry; int i, err;
for (i = start; i < eof; i++) { switch (files[i].mode & S_IFMT) { default:
BUG(); case S_IFREG:
err = rpc_new_file(parent,
files[i].name,
files[i].mode,
files[i].i_fop, private); if (err) goto out_bad; break; case S_IFDIR:
dentry = rpc_new_dir(parent,
files[i].name,
files[i].mode); if (IS_ERR(dentry)) {
err = PTR_ERR(dentry); goto out_bad;
}
}
} return 0;
out_bad:
printk(KERN_WARNING "%s: %s failed to populate directory %pd\n",
__FILE__, __func__, parent); return err;
}
/** * rpc_mkpipe_dentry - make an rpc_pipefs file for kernel<->userspace * communication * @parent: dentry of directory to create new "pipe" in * @name: name of pipe * @private: private data to associate with the pipe, for the caller's use * @pipe: &rpc_pipe containing input parameters * * Data is made available for userspace to read by calls to * rpc_queue_upcall(). The actual reads will result in calls to * @ops->upcall, which will be called with the file pointer, * message, and userspace buffer to copy to. * * Writes can come at any time, and do not necessarily have to be * responses to upcalls. They will result in calls to @msg->downcall. * * The @private argument passed here will be available to all these methods * from the file pointer, via RPC_I(file_inode(file))->private.
*/ int rpc_mkpipe_dentry(struct dentry *parent, constchar *name, void *private, struct rpc_pipe *pipe)
{ struct inode *dir = d_inode(parent); struct dentry *dentry; struct inode *inode; struct rpc_inode *rpci;
umode_t umode = S_IFIFO | 0600; int err;
if (pipe->ops->upcall == NULL)
umode &= ~0444; if (pipe->ops->downcall == NULL)
umode &= ~0222;
/** * rpc_unlink - remove a pipe * @pipe: the pipe to be removed * * After this call, lookups will no longer find the pipe, and any * attempts to read or write using preexisting opens of the pipe will * return -EPIPE.
*/ void
rpc_unlink(struct rpc_pipe *pipe)
{ if (pipe->dentry) {
simple_recursive_removal(pipe->dentry, rpc_close_pipes);
pipe->dentry = NULL;
}
}
EXPORT_SYMBOL_GPL(rpc_unlink);
/** * rpc_init_pipe_dir_object - initialise a struct rpc_pipe_dir_object * @pdo: pointer to struct rpc_pipe_dir_object * @pdo_ops: pointer to const struct rpc_pipe_dir_object_ops * @pdo_data: pointer to caller-defined data
*/ void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo, conststruct rpc_pipe_dir_object_ops *pdo_ops, void *pdo_data)
{
INIT_LIST_HEAD(&pdo->pdo_head);
pdo->pdo_ops = pdo_ops;
pdo->pdo_data = pdo_data;
}
EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_object);
staticint
rpc_add_pipe_dir_object_locked(struct net *net, struct rpc_pipe_dir_head *pdh, struct rpc_pipe_dir_object *pdo)
{ int ret = 0;
if (pdh->pdh_dentry)
ret = pdo->pdo_ops->create(pdh->pdh_dentry, pdo); if (ret == 0)
list_add_tail(&pdo->pdo_head, &pdh->pdh_entries); return ret;
}
staticvoid
rpc_remove_pipe_dir_object_locked(struct net *net, struct rpc_pipe_dir_head *pdh, struct rpc_pipe_dir_object *pdo)
{ if (pdh->pdh_dentry)
pdo->pdo_ops->destroy(pdh->pdh_dentry, pdo);
list_del_init(&pdo->pdo_head);
}
/** * rpc_add_pipe_dir_object - associate a rpc_pipe_dir_object to a directory * @net: pointer to struct net * @pdh: pointer to struct rpc_pipe_dir_head * @pdo: pointer to struct rpc_pipe_dir_object *
*/ int
rpc_add_pipe_dir_object(struct net *net, struct rpc_pipe_dir_head *pdh, struct rpc_pipe_dir_object *pdo)
{ int ret = 0;
if (list_empty(&pdo->pdo_head)) { struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
/** * rpc_find_or_alloc_pipe_dir_object * @net: pointer to struct net * @pdh: pointer to struct rpc_pipe_dir_head * @match: match struct rpc_pipe_dir_object to data * @alloc: allocate a new struct rpc_pipe_dir_object * @data: user defined data for match() and alloc() *
*/ struct rpc_pipe_dir_object *
rpc_find_or_alloc_pipe_dir_object(struct net *net, struct rpc_pipe_dir_head *pdh, int (*match)(struct rpc_pipe_dir_object *, void *), struct rpc_pipe_dir_object *(*alloc)(void *), void *data)
{ struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); struct rpc_pipe_dir_object *pdo;
/** * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs * @dentry: the parent of new directory * @name: the name of new directory * @rpc_client: rpc client to associate with this directory * * This creates a directory at the given @path associated with * @rpc_clnt, which will contain a file named "info" with some basic * information about the client, together with any "pipes" that may * later be created using rpc_mkpipe().
*/ int rpc_create_client_dir(struct dentry *dentry, constchar *name, struct rpc_clnt *rpc_client)
{ struct dentry *ret; int err;
/** * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() * @rpc_client: rpc_client for the pipe
*/ int rpc_remove_client_dir(struct rpc_clnt *rpc_client)
{ struct dentry *dentry = rpc_client->cl_pipedir_objects.pdh_dentry;
/* * We have a single directory with 1 node in it.
*/ enum {
RPCAUTH_lockd,
RPCAUTH_mount,
RPCAUTH_nfs,
RPCAUTH_portmap,
RPCAUTH_statd,
RPCAUTH_nfsd4_cb,
RPCAUTH_cache,
RPCAUTH_nfsd,
RPCAUTH_RootEOF
};
/* * This call can be used only in RPC pipefs mount notification hooks.
*/ struct dentry *rpc_d_lookup_sb(conststruct super_block *sb, constunsignedchar *dir_name)
{ return try_lookup_noperm(&QSTR(dir_name), sb->s_root);
}
EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
int rpc_pipefs_init_net(struct net *net)
{ struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0); if (IS_ERR(sn->gssd_dummy)) return PTR_ERR(sn->gssd_dummy);
/* * This call will be used for per network namespace operations calls. * Note: Function will be returned with pipefs_sb_lock taken if superblock was * found. This lock have to be released by rpc_put_sb_net() when all operations * will be completed.
*/ struct super_block *rpc_get_sb_net(conststruct net *net)
{ struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
mutex_lock(&sn->pipefs_sb_lock); if (sn->pipefs_sb) return sn->pipefs_sb;
mutex_unlock(&sn->pipefs_sb_lock); return NULL;
}
EXPORT_SYMBOL_GPL(rpc_get_sb_net);
/* * Here we present a bogus "info" file to keep rpc.gssd happy. We don't expect * that it will ever use this info to handle an upcall, but rpc.gssd expects * that this file will be there and have a certain format.
*/ staticint
rpc_dummy_info_show(struct seq_file *m, void *v)
{
seq_printf(m, "RPC server: %s\n", utsname()->nodename);
seq_printf(m, "service: foo (1) version 0\n");
seq_printf(m, "address: 127.0.0.1\n");
seq_printf(m, "protocol: tcp\n");
seq_printf(m, "port: 0\n"); return 0;
}
DEFINE_SHOW_ATTRIBUTE(rpc_dummy_info);
/** * rpc_gssd_dummy_populate - create a dummy gssd pipe * @root: root of the rpc_pipefs filesystem * @pipe_data: pipe data created when netns is initialized * * Create a dummy set of directories and a pipe that gssd can hold open to * indicate that it is up and running.
*/ staticint
rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
{ struct dentry *gssd_dentry, *clnt_dentry; int err;
gssd_dentry = rpc_new_dir(root, "gssd", 0555); if (IS_ERR(gssd_dentry)) return -ENOENT;
clnt_dentry = rpc_new_dir(gssd_dentry, "clntXX", 0555); if (IS_ERR(clnt_dentry)) return -ENOENT;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.