Merge branch 'sunrpc_cache-for-2.6.32' into nfs-for-2.6.32
This commit is contained in:
Коммит
f884dcaead
|
@ -101,7 +101,7 @@ static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
|
|||
|
||||
static unsigned int fnvhash32(const void *, size_t);
|
||||
|
||||
static struct rpc_pipe_ops idmap_upcall_ops = {
|
||||
static const struct rpc_pipe_ops idmap_upcall_ops = {
|
||||
.upcall = idmap_pipe_upcall,
|
||||
.downcall = idmap_pipe_downcall,
|
||||
.destroy_msg = idmap_pipe_destroy_msg,
|
||||
|
@ -119,8 +119,8 @@ nfs_idmap_new(struct nfs_client *clp)
|
|||
if (idmap == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap",
|
||||
idmap, &idmap_upcall_ops, 0);
|
||||
idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry,
|
||||
"idmap", idmap, &idmap_upcall_ops, 0);
|
||||
if (IS_ERR(idmap->idmap_dentry)) {
|
||||
error = PTR_ERR(idmap->idmap_dentry);
|
||||
kfree(idmap);
|
||||
|
|
|
@ -85,6 +85,11 @@ static void expkey_request(struct cache_detail *cd,
|
|||
(*bpp)[-1] = '\n';
|
||||
}
|
||||
|
||||
static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall(cd, h, expkey_request);
|
||||
}
|
||||
|
||||
static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old);
|
||||
static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
|
||||
static struct cache_detail svc_expkey_cache;
|
||||
|
@ -259,7 +264,7 @@ static struct cache_detail svc_expkey_cache = {
|
|||
.hash_table = expkey_table,
|
||||
.name = "nfsd.fh",
|
||||
.cache_put = expkey_put,
|
||||
.cache_request = expkey_request,
|
||||
.cache_upcall = expkey_upcall,
|
||||
.cache_parse = expkey_parse,
|
||||
.cache_show = expkey_show,
|
||||
.match = expkey_match,
|
||||
|
@ -355,6 +360,11 @@ static void svc_export_request(struct cache_detail *cd,
|
|||
(*bpp)[-1] = '\n';
|
||||
}
|
||||
|
||||
static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall(cd, h, svc_export_request);
|
||||
}
|
||||
|
||||
static struct svc_export *svc_export_update(struct svc_export *new,
|
||||
struct svc_export *old);
|
||||
static struct svc_export *svc_export_lookup(struct svc_export *);
|
||||
|
@ -724,7 +734,7 @@ struct cache_detail svc_export_cache = {
|
|||
.hash_table = export_table,
|
||||
.name = "nfsd.export",
|
||||
.cache_put = svc_export_put,
|
||||
.cache_request = svc_export_request,
|
||||
.cache_upcall = svc_export_upcall,
|
||||
.cache_parse = svc_export_parse,
|
||||
.cache_show = svc_export_show,
|
||||
.match = svc_export_match,
|
||||
|
|
|
@ -145,6 +145,12 @@ idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
|
|||
(*bpp)[-1] = '\n';
|
||||
}
|
||||
|
||||
static int
|
||||
idtoname_upcall(struct cache_detail *cd, struct cache_head *ch)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall(cd, ch, idtoname_request);
|
||||
}
|
||||
|
||||
static int
|
||||
idtoname_match(struct cache_head *ca, struct cache_head *cb)
|
||||
{
|
||||
|
@ -175,10 +181,10 @@ idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
|
|||
}
|
||||
|
||||
static void
|
||||
warn_no_idmapd(struct cache_detail *detail)
|
||||
warn_no_idmapd(struct cache_detail *detail, int has_died)
|
||||
{
|
||||
printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n",
|
||||
detail->last_close? "died" : "not been started");
|
||||
has_died ? "died" : "not been started");
|
||||
}
|
||||
|
||||
|
||||
|
@ -192,7 +198,7 @@ static struct cache_detail idtoname_cache = {
|
|||
.hash_table = idtoname_table,
|
||||
.name = "nfs4.idtoname",
|
||||
.cache_put = ent_put,
|
||||
.cache_request = idtoname_request,
|
||||
.cache_upcall = idtoname_upcall,
|
||||
.cache_parse = idtoname_parse,
|
||||
.cache_show = idtoname_show,
|
||||
.warn_no_listener = warn_no_idmapd,
|
||||
|
@ -324,6 +330,12 @@ nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
|
|||
(*bpp)[-1] = '\n';
|
||||
}
|
||||
|
||||
static int
|
||||
nametoid_upcall(struct cache_detail *cd, struct cache_head *ch)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall(cd, ch, nametoid_request);
|
||||
}
|
||||
|
||||
static int
|
||||
nametoid_match(struct cache_head *ca, struct cache_head *cb)
|
||||
{
|
||||
|
@ -363,7 +375,7 @@ static struct cache_detail nametoid_cache = {
|
|||
.hash_table = nametoid_table,
|
||||
.name = "nfs4.nametoid",
|
||||
.cache_put = ent_put,
|
||||
.cache_request = nametoid_request,
|
||||
.cache_upcall = nametoid_upcall,
|
||||
.cache_parse = nametoid_parse,
|
||||
.cache_show = nametoid_show,
|
||||
.warn_no_listener = warn_no_idmapd,
|
||||
|
|
|
@ -59,6 +59,15 @@ struct cache_head {
|
|||
|
||||
#define CACHE_NEW_EXPIRY 120 /* keep new things pending confirmation for 120 seconds */
|
||||
|
||||
struct cache_detail_procfs {
|
||||
struct proc_dir_entry *proc_ent;
|
||||
struct proc_dir_entry *flush_ent, *channel_ent, *content_ent;
|
||||
};
|
||||
|
||||
struct cache_detail_pipefs {
|
||||
struct dentry *dir;
|
||||
};
|
||||
|
||||
struct cache_detail {
|
||||
struct module * owner;
|
||||
int hash_size;
|
||||
|
@ -70,15 +79,17 @@ struct cache_detail {
|
|||
char *name;
|
||||
void (*cache_put)(struct kref *);
|
||||
|
||||
void (*cache_request)(struct cache_detail *cd,
|
||||
struct cache_head *h,
|
||||
char **bpp, int *blen);
|
||||
int (*cache_upcall)(struct cache_detail *,
|
||||
struct cache_head *);
|
||||
|
||||
int (*cache_parse)(struct cache_detail *,
|
||||
char *buf, int len);
|
||||
|
||||
int (*cache_show)(struct seq_file *m,
|
||||
struct cache_detail *cd,
|
||||
struct cache_head *h);
|
||||
void (*warn_no_listener)(struct cache_detail *cd,
|
||||
int has_died);
|
||||
|
||||
struct cache_head * (*alloc)(void);
|
||||
int (*match)(struct cache_head *orig, struct cache_head *new);
|
||||
|
@ -96,13 +107,15 @@ struct cache_detail {
|
|||
|
||||
/* fields for communication over channel */
|
||||
struct list_head queue;
|
||||
struct proc_dir_entry *proc_ent;
|
||||
struct proc_dir_entry *flush_ent, *channel_ent, *content_ent;
|
||||
|
||||
atomic_t readers; /* how many time is /chennel open */
|
||||
time_t last_close; /* if no readers, when did last close */
|
||||
time_t last_warn; /* when we last warned about no readers */
|
||||
void (*warn_no_listener)(struct cache_detail *cd);
|
||||
|
||||
union {
|
||||
struct cache_detail_procfs procfs;
|
||||
struct cache_detail_pipefs pipefs;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
|
@ -127,6 +140,10 @@ struct cache_deferred_req {
|
|||
};
|
||||
|
||||
|
||||
extern const struct file_operations cache_file_operations_pipefs;
|
||||
extern const struct file_operations content_file_operations_pipefs;
|
||||
extern const struct file_operations cache_flush_operations_pipefs;
|
||||
|
||||
extern struct cache_head *
|
||||
sunrpc_cache_lookup(struct cache_detail *detail,
|
||||
struct cache_head *key, int hash);
|
||||
|
@ -134,6 +151,13 @@ extern struct cache_head *
|
|||
sunrpc_cache_update(struct cache_detail *detail,
|
||||
struct cache_head *new, struct cache_head *old, int hash);
|
||||
|
||||
extern int
|
||||
sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h,
|
||||
void (*cache_request)(struct cache_detail *,
|
||||
struct cache_head *,
|
||||
char **,
|
||||
int *));
|
||||
|
||||
|
||||
extern void cache_clean_deferred(void *owner);
|
||||
|
||||
|
@ -171,6 +195,10 @@ extern void cache_purge(struct cache_detail *detail);
|
|||
extern int cache_register(struct cache_detail *cd);
|
||||
extern void cache_unregister(struct cache_detail *cd);
|
||||
|
||||
extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
|
||||
mode_t, struct cache_detail *);
|
||||
extern void sunrpc_cache_unregister_pipefs(struct cache_detail *);
|
||||
|
||||
extern void qword_add(char **bpp, int *lp, char *str);
|
||||
extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
|
||||
extern int qword_get(char **bpp, char *dest, int bufsize);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/timer.h>
|
||||
#include <asm/signal.h>
|
||||
#include <linux/path.h>
|
||||
|
||||
struct rpc_inode;
|
||||
|
||||
|
@ -54,9 +55,7 @@ struct rpc_clnt {
|
|||
|
||||
int cl_nodelen; /* nodename length */
|
||||
char cl_nodename[UNX_MAXNODENAME];
|
||||
char cl_pathname[30];/* Path in rpc_pipe_fs */
|
||||
struct vfsmount * cl_vfsmnt;
|
||||
struct dentry * cl_dentry; /* inode */
|
||||
struct path cl_path;
|
||||
struct rpc_clnt * cl_parent; /* Points to parent of clones */
|
||||
struct rpc_rtt cl_rtt_default;
|
||||
struct rpc_timeout cl_timeout_default;
|
||||
|
|
|
@ -32,8 +32,8 @@ struct rpc_inode {
|
|||
wait_queue_head_t waitq;
|
||||
#define RPC_PIPE_WAIT_FOR_OPEN 1
|
||||
int flags;
|
||||
struct rpc_pipe_ops *ops;
|
||||
struct delayed_work queue_timeout;
|
||||
const struct rpc_pipe_ops *ops;
|
||||
};
|
||||
|
||||
static inline struct rpc_inode *
|
||||
|
@ -44,9 +44,19 @@ RPC_I(struct inode *inode)
|
|||
|
||||
extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
|
||||
|
||||
extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
|
||||
extern int rpc_rmdir(struct dentry *);
|
||||
extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, struct rpc_pipe_ops *, int flags);
|
||||
struct rpc_clnt;
|
||||
extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *);
|
||||
extern int rpc_remove_client_dir(struct dentry *);
|
||||
|
||||
struct cache_detail;
|
||||
extern struct dentry *rpc_create_cache_dir(struct dentry *,
|
||||
struct qstr *,
|
||||
mode_t umode,
|
||||
struct cache_detail *);
|
||||
extern void rpc_remove_cache_dir(struct dentry *);
|
||||
|
||||
extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *,
|
||||
const struct rpc_pipe_ops *, int flags);
|
||||
extern int rpc_unlink(struct dentry *);
|
||||
extern struct vfsmount *rpc_get_mount(void);
|
||||
extern void rpc_put_mount(void);
|
||||
|
|
|
@ -89,8 +89,8 @@ static struct rpc_wait_queue pipe_version_rpc_waitqueue;
|
|||
static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
|
||||
|
||||
static void gss_free_ctx(struct gss_cl_ctx *);
|
||||
static struct rpc_pipe_ops gss_upcall_ops_v0;
|
||||
static struct rpc_pipe_ops gss_upcall_ops_v1;
|
||||
static const struct rpc_pipe_ops gss_upcall_ops_v0;
|
||||
static const struct rpc_pipe_ops gss_upcall_ops_v1;
|
||||
|
||||
static inline struct gss_cl_ctx *
|
||||
gss_get_ctx(struct gss_cl_ctx *ctx)
|
||||
|
@ -777,7 +777,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
|
|||
* that we supported only the old pipe. So we instead create
|
||||
* the new pipe first.
|
||||
*/
|
||||
gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_dentry,
|
||||
gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_path.dentry,
|
||||
"gssd",
|
||||
clnt, &gss_upcall_ops_v1,
|
||||
RPC_PIPE_WAIT_FOR_OPEN);
|
||||
|
@ -786,7 +786,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
|
|||
goto err_put_mech;
|
||||
}
|
||||
|
||||
gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_dentry,
|
||||
gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_path.dentry,
|
||||
gss_auth->mech->gm_name,
|
||||
clnt, &gss_upcall_ops_v0,
|
||||
RPC_PIPE_WAIT_FOR_OPEN);
|
||||
|
@ -1507,7 +1507,7 @@ static const struct rpc_credops gss_nullops = {
|
|||
.crunwrap_resp = gss_unwrap_resp,
|
||||
};
|
||||
|
||||
static struct rpc_pipe_ops gss_upcall_ops_v0 = {
|
||||
static const struct rpc_pipe_ops gss_upcall_ops_v0 = {
|
||||
.upcall = gss_pipe_upcall,
|
||||
.downcall = gss_pipe_downcall,
|
||||
.destroy_msg = gss_pipe_destroy_msg,
|
||||
|
@ -1515,7 +1515,7 @@ static struct rpc_pipe_ops gss_upcall_ops_v0 = {
|
|||
.release_pipe = gss_pipe_release,
|
||||
};
|
||||
|
||||
static struct rpc_pipe_ops gss_upcall_ops_v1 = {
|
||||
static const struct rpc_pipe_ops gss_upcall_ops_v1 = {
|
||||
.upcall = gss_pipe_upcall,
|
||||
.downcall = gss_pipe_downcall,
|
||||
.destroy_msg = gss_pipe_destroy_msg,
|
||||
|
|
|
@ -181,6 +181,11 @@ static void rsi_request(struct cache_detail *cd,
|
|||
(*bpp)[-1] = '\n';
|
||||
}
|
||||
|
||||
static int rsi_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall(cd, h, rsi_request);
|
||||
}
|
||||
|
||||
|
||||
static int rsi_parse(struct cache_detail *cd,
|
||||
char *mesg, int mlen)
|
||||
|
@ -270,7 +275,7 @@ static struct cache_detail rsi_cache = {
|
|||
.hash_table = rsi_table,
|
||||
.name = "auth.rpcsec.init",
|
||||
.cache_put = rsi_put,
|
||||
.cache_request = rsi_request,
|
||||
.cache_upcall = rsi_upcall,
|
||||
.cache_parse = rsi_parse,
|
||||
.match = rsi_match,
|
||||
.init = rsi_init,
|
||||
|
|
|
@ -27,10 +27,12 @@
|
|||
#include <linux/net.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <asm/ioctls.h>
|
||||
#include <linux/sunrpc/types.h>
|
||||
#include <linux/sunrpc/cache.h>
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_CACHE
|
||||
|
||||
|
@ -175,7 +177,13 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_update);
|
||||
|
||||
static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h);
|
||||
static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
if (!cd->cache_upcall)
|
||||
return -EINVAL;
|
||||
return cd->cache_upcall(cd, h);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the generic cache management routine for all
|
||||
* the authentication caches.
|
||||
|
@ -284,76 +292,11 @@ static DEFINE_SPINLOCK(cache_list_lock);
|
|||
static struct cache_detail *current_detail;
|
||||
static int current_index;
|
||||
|
||||
static const struct file_operations cache_file_operations;
|
||||
static const struct file_operations content_file_operations;
|
||||
static const struct file_operations cache_flush_operations;
|
||||
|
||||
static void do_cache_clean(struct work_struct *work);
|
||||
static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean);
|
||||
|
||||
static void remove_cache_proc_entries(struct cache_detail *cd)
|
||||
static void sunrpc_init_cache_detail(struct cache_detail *cd)
|
||||
{
|
||||
if (cd->proc_ent == NULL)
|
||||
return;
|
||||
if (cd->flush_ent)
|
||||
remove_proc_entry("flush", cd->proc_ent);
|
||||
if (cd->channel_ent)
|
||||
remove_proc_entry("channel", cd->proc_ent);
|
||||
if (cd->content_ent)
|
||||
remove_proc_entry("content", cd->proc_ent);
|
||||
cd->proc_ent = NULL;
|
||||
remove_proc_entry(cd->name, proc_net_rpc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static int create_cache_proc_entries(struct cache_detail *cd)
|
||||
{
|
||||
struct proc_dir_entry *p;
|
||||
|
||||
cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
|
||||
if (cd->proc_ent == NULL)
|
||||
goto out_nomem;
|
||||
cd->channel_ent = cd->content_ent = NULL;
|
||||
|
||||
p = proc_create_data("flush", S_IFREG|S_IRUSR|S_IWUSR,
|
||||
cd->proc_ent, &cache_flush_operations, cd);
|
||||
cd->flush_ent = p;
|
||||
if (p == NULL)
|
||||
goto out_nomem;
|
||||
|
||||
if (cd->cache_request || cd->cache_parse) {
|
||||
p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR,
|
||||
cd->proc_ent, &cache_file_operations, cd);
|
||||
cd->channel_ent = p;
|
||||
if (p == NULL)
|
||||
goto out_nomem;
|
||||
}
|
||||
if (cd->cache_show) {
|
||||
p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR,
|
||||
cd->proc_ent, &content_file_operations, cd);
|
||||
cd->content_ent = p;
|
||||
if (p == NULL)
|
||||
goto out_nomem;
|
||||
}
|
||||
return 0;
|
||||
out_nomem:
|
||||
remove_cache_proc_entries(cd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#else /* CONFIG_PROC_FS */
|
||||
static int create_cache_proc_entries(struct cache_detail *cd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int cache_register(struct cache_detail *cd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = create_cache_proc_entries(cd);
|
||||
if (ret)
|
||||
return ret;
|
||||
rwlock_init(&cd->hash_lock);
|
||||
INIT_LIST_HEAD(&cd->queue);
|
||||
spin_lock(&cache_list_lock);
|
||||
|
@ -367,11 +310,9 @@ int cache_register(struct cache_detail *cd)
|
|||
|
||||
/* start the cleaning process */
|
||||
schedule_delayed_work(&cache_cleaner, 0);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cache_register);
|
||||
|
||||
void cache_unregister(struct cache_detail *cd)
|
||||
static void sunrpc_destroy_cache_detail(struct cache_detail *cd)
|
||||
{
|
||||
cache_purge(cd);
|
||||
spin_lock(&cache_list_lock);
|
||||
|
@ -386,7 +327,6 @@ void cache_unregister(struct cache_detail *cd)
|
|||
list_del_init(&cd->others);
|
||||
write_unlock(&cd->hash_lock);
|
||||
spin_unlock(&cache_list_lock);
|
||||
remove_cache_proc_entries(cd);
|
||||
if (list_empty(&cache_list)) {
|
||||
/* module must be being unloaded so its safe to kill the worker */
|
||||
cancel_delayed_work_sync(&cache_cleaner);
|
||||
|
@ -395,7 +335,6 @@ void cache_unregister(struct cache_detail *cd)
|
|||
out:
|
||||
printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cache_unregister);
|
||||
|
||||
/* clean cache tries to find something to clean
|
||||
* and cleans it.
|
||||
|
@ -687,18 +626,18 @@ struct cache_reader {
|
|||
int offset; /* if non-0, we have a refcnt on next request */
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
|
||||
static ssize_t cache_read(struct file *filp, char __user *buf, size_t count,
|
||||
loff_t *ppos, struct cache_detail *cd)
|
||||
{
|
||||
struct cache_reader *rp = filp->private_data;
|
||||
struct cache_request *rq;
|
||||
struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
|
||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||
int err;
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&queue_io_mutex); /* protect against multiple concurrent
|
||||
mutex_lock(&inode->i_mutex); /* protect against multiple concurrent
|
||||
* readers on this file */
|
||||
again:
|
||||
spin_lock(&queue_lock);
|
||||
|
@ -711,7 +650,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
|
|||
}
|
||||
if (rp->q.list.next == &cd->queue) {
|
||||
spin_unlock(&queue_lock);
|
||||
mutex_unlock(&queue_io_mutex);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
BUG_ON(rp->offset);
|
||||
return 0;
|
||||
}
|
||||
|
@ -758,49 +697,90 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
|
|||
}
|
||||
if (err == -EAGAIN)
|
||||
goto again;
|
||||
mutex_unlock(&queue_io_mutex);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return err ? err : count;
|
||||
}
|
||||
|
||||
static char write_buf[8192]; /* protected by queue_io_mutex */
|
||||
|
||||
static ssize_t
|
||||
cache_write(struct file *filp, const char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
static ssize_t cache_do_downcall(char *kaddr, const char __user *buf,
|
||||
size_t count, struct cache_detail *cd)
|
||||
{
|
||||
int err;
|
||||
struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
|
||||
ssize_t ret;
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
if (count >= sizeof(write_buf))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&queue_io_mutex);
|
||||
|
||||
if (copy_from_user(write_buf, buf, count)) {
|
||||
mutex_unlock(&queue_io_mutex);
|
||||
if (copy_from_user(kaddr, buf, count))
|
||||
return -EFAULT;
|
||||
}
|
||||
write_buf[count] = '\0';
|
||||
if (cd->cache_parse)
|
||||
err = cd->cache_parse(cd, write_buf, count);
|
||||
else
|
||||
err = -EINVAL;
|
||||
kaddr[count] = '\0';
|
||||
ret = cd->cache_parse(cd, kaddr, count);
|
||||
if (!ret)
|
||||
ret = count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t cache_slow_downcall(const char __user *buf,
|
||||
size_t count, struct cache_detail *cd)
|
||||
{
|
||||
static char write_buf[8192]; /* protected by queue_io_mutex */
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
if (count >= sizeof(write_buf))
|
||||
goto out;
|
||||
mutex_lock(&queue_io_mutex);
|
||||
ret = cache_do_downcall(write_buf, buf, count, cd);
|
||||
mutex_unlock(&queue_io_mutex);
|
||||
return err ? err : count;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t cache_downcall(struct address_space *mapping,
|
||||
const char __user *buf,
|
||||
size_t count, struct cache_detail *cd)
|
||||
{
|
||||
struct page *page;
|
||||
char *kaddr;
|
||||
ssize_t ret = -ENOMEM;
|
||||
|
||||
if (count >= PAGE_CACHE_SIZE)
|
||||
goto out_slow;
|
||||
|
||||
page = find_or_create_page(mapping, 0, GFP_KERNEL);
|
||||
if (!page)
|
||||
goto out_slow;
|
||||
|
||||
kaddr = kmap(page);
|
||||
ret = cache_do_downcall(kaddr, buf, count, cd);
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
return ret;
|
||||
out_slow:
|
||||
return cache_slow_downcall(buf, count, cd);
|
||||
}
|
||||
|
||||
static ssize_t cache_write(struct file *filp, const char __user *buf,
|
||||
size_t count, loff_t *ppos,
|
||||
struct cache_detail *cd)
|
||||
{
|
||||
struct address_space *mapping = filp->f_mapping;
|
||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
if (!cd->cache_parse)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
ret = cache_downcall(mapping, buf, count, cd);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(queue_wait);
|
||||
|
||||
static unsigned int
|
||||
cache_poll(struct file *filp, poll_table *wait)
|
||||
static unsigned int cache_poll(struct file *filp, poll_table *wait,
|
||||
struct cache_detail *cd)
|
||||
{
|
||||
unsigned int mask;
|
||||
struct cache_reader *rp = filp->private_data;
|
||||
struct cache_queue *cq;
|
||||
struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
|
||||
|
||||
poll_wait(filp, &queue_wait, wait);
|
||||
|
||||
|
@ -822,14 +802,13 @@ cache_poll(struct file *filp, poll_table *wait)
|
|||
return mask;
|
||||
}
|
||||
|
||||
static int
|
||||
cache_ioctl(struct inode *ino, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int cache_ioctl(struct inode *ino, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg,
|
||||
struct cache_detail *cd)
|
||||
{
|
||||
int len = 0;
|
||||
struct cache_reader *rp = filp->private_data;
|
||||
struct cache_queue *cq;
|
||||
struct cache_detail *cd = PDE(ino)->data;
|
||||
|
||||
if (cmd != FIONREAD || !rp)
|
||||
return -EINVAL;
|
||||
|
@ -852,15 +831,13 @@ cache_ioctl(struct inode *ino, struct file *filp,
|
|||
return put_user(len, (int __user *)arg);
|
||||
}
|
||||
|
||||
static int
|
||||
cache_open(struct inode *inode, struct file *filp)
|
||||
static int cache_open(struct inode *inode, struct file *filp,
|
||||
struct cache_detail *cd)
|
||||
{
|
||||
struct cache_reader *rp = NULL;
|
||||
|
||||
nonseekable_open(inode, filp);
|
||||
if (filp->f_mode & FMODE_READ) {
|
||||
struct cache_detail *cd = PDE(inode)->data;
|
||||
|
||||
rp = kmalloc(sizeof(*rp), GFP_KERNEL);
|
||||
if (!rp)
|
||||
return -ENOMEM;
|
||||
|
@ -875,11 +852,10 @@ cache_open(struct inode *inode, struct file *filp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cache_release(struct inode *inode, struct file *filp)
|
||||
static int cache_release(struct inode *inode, struct file *filp,
|
||||
struct cache_detail *cd)
|
||||
{
|
||||
struct cache_reader *rp = filp->private_data;
|
||||
struct cache_detail *cd = PDE(inode)->data;
|
||||
|
||||
if (rp) {
|
||||
spin_lock(&queue_lock);
|
||||
|
@ -908,18 +884,6 @@ cache_release(struct inode *inode, struct file *filp)
|
|||
|
||||
|
||||
|
||||
static const struct file_operations cache_file_operations = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.read = cache_read,
|
||||
.write = cache_write,
|
||||
.poll = cache_poll,
|
||||
.ioctl = cache_ioctl, /* for FIONREAD */
|
||||
.open = cache_open,
|
||||
.release = cache_release,
|
||||
};
|
||||
|
||||
|
||||
static void queue_loose(struct cache_detail *detail, struct cache_head *ch)
|
||||
{
|
||||
struct cache_queue *cq;
|
||||
|
@ -1020,15 +984,21 @@ static void warn_no_listener(struct cache_detail *detail)
|
|||
if (detail->last_warn != detail->last_close) {
|
||||
detail->last_warn = detail->last_close;
|
||||
if (detail->warn_no_listener)
|
||||
detail->warn_no_listener(detail);
|
||||
detail->warn_no_listener(detail, detail->last_close != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* register an upcall request to user-space.
|
||||
* register an upcall request to user-space and queue it up for read() by the
|
||||
* upcall daemon.
|
||||
*
|
||||
* Each request is at most one page long.
|
||||
*/
|
||||
static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h)
|
||||
int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h,
|
||||
void (*cache_request)(struct cache_detail *,
|
||||
struct cache_head *,
|
||||
char **,
|
||||
int *))
|
||||
{
|
||||
|
||||
char *buf;
|
||||
|
@ -1036,9 +1006,6 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h)
|
|||
char *bp;
|
||||
int len;
|
||||
|
||||
if (detail->cache_request == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (atomic_read(&detail->readers) == 0 &&
|
||||
detail->last_close < get_seconds() - 30) {
|
||||
warn_no_listener(detail);
|
||||
|
@ -1057,7 +1024,7 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h)
|
|||
|
||||
bp = buf; len = PAGE_SIZE;
|
||||
|
||||
detail->cache_request(detail, h, &bp, &len);
|
||||
cache_request(detail, h, &bp, &len);
|
||||
|
||||
if (len < 0) {
|
||||
kfree(buf);
|
||||
|
@ -1075,6 +1042,7 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h)
|
|||
wake_up(&queue_wait);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall);
|
||||
|
||||
/*
|
||||
* parse a message from user-space and pass it
|
||||
|
@ -1242,10 +1210,10 @@ static const struct seq_operations cache_content_op = {
|
|||
.show = c_show,
|
||||
};
|
||||
|
||||
static int content_open(struct inode *inode, struct file *file)
|
||||
static int content_open(struct inode *inode, struct file *file,
|
||||
struct cache_detail *cd)
|
||||
{
|
||||
struct handle *han;
|
||||
struct cache_detail *cd = PDE(inode)->data;
|
||||
|
||||
han = __seq_open_private(file, &cache_content_op, sizeof(*han));
|
||||
if (han == NULL)
|
||||
|
@ -1255,17 +1223,10 @@ static int content_open(struct inode *inode, struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations content_file_operations = {
|
||||
.open = content_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release_private,
|
||||
};
|
||||
|
||||
static ssize_t read_flush(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
size_t count, loff_t *ppos,
|
||||
struct cache_detail *cd)
|
||||
{
|
||||
struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data;
|
||||
char tbuf[20];
|
||||
unsigned long p = *ppos;
|
||||
size_t len;
|
||||
|
@ -1283,10 +1244,10 @@ static ssize_t read_flush(struct file *file, char __user *buf,
|
|||
return len;
|
||||
}
|
||||
|
||||
static ssize_t write_flush(struct file * file, const char __user * buf,
|
||||
size_t count, loff_t *ppos)
|
||||
static ssize_t write_flush(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos,
|
||||
struct cache_detail *cd)
|
||||
{
|
||||
struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data;
|
||||
char tbuf[20];
|
||||
char *ep;
|
||||
long flushtime;
|
||||
|
@ -1307,8 +1268,299 @@ static ssize_t write_flush(struct file * file, const char __user * buf,
|
|||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations cache_flush_operations = {
|
||||
.open = nonseekable_open,
|
||||
.read = read_flush,
|
||||
.write = write_flush,
|
||||
static ssize_t cache_read_procfs(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
|
||||
|
||||
return cache_read(filp, buf, count, ppos, cd);
|
||||
}
|
||||
|
||||
static ssize_t cache_write_procfs(struct file *filp, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
|
||||
|
||||
return cache_write(filp, buf, count, ppos, cd);
|
||||
}
|
||||
|
||||
static unsigned int cache_poll_procfs(struct file *filp, poll_table *wait)
|
||||
{
|
||||
struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
|
||||
|
||||
return cache_poll(filp, wait, cd);
|
||||
}
|
||||
|
||||
static int cache_ioctl_procfs(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct cache_detail *cd = PDE(inode)->data;
|
||||
|
||||
return cache_ioctl(inode, filp, cmd, arg, cd);
|
||||
}
|
||||
|
||||
static int cache_open_procfs(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct cache_detail *cd = PDE(inode)->data;
|
||||
|
||||
return cache_open(inode, filp, cd);
|
||||
}
|
||||
|
||||
static int cache_release_procfs(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct cache_detail *cd = PDE(inode)->data;
|
||||
|
||||
return cache_release(inode, filp, cd);
|
||||
}
|
||||
|
||||
static const struct file_operations cache_file_operations_procfs = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.read = cache_read_procfs,
|
||||
.write = cache_write_procfs,
|
||||
.poll = cache_poll_procfs,
|
||||
.ioctl = cache_ioctl_procfs, /* for FIONREAD */
|
||||
.open = cache_open_procfs,
|
||||
.release = cache_release_procfs,
|
||||
};
|
||||
|
||||
static int content_open_procfs(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct cache_detail *cd = PDE(inode)->data;
|
||||
|
||||
return content_open(inode, filp, cd);
|
||||
}
|
||||
|
||||
static const struct file_operations content_file_operations_procfs = {
|
||||
.open = content_open_procfs,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release_private,
|
||||
};
|
||||
|
||||
static ssize_t read_flush_procfs(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
|
||||
|
||||
return read_flush(filp, buf, count, ppos, cd);
|
||||
}
|
||||
|
||||
static ssize_t write_flush_procfs(struct file *filp,
|
||||
const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
|
||||
|
||||
return write_flush(filp, buf, count, ppos, cd);
|
||||
}
|
||||
|
||||
static const struct file_operations cache_flush_operations_procfs = {
|
||||
.open = nonseekable_open,
|
||||
.read = read_flush_procfs,
|
||||
.write = write_flush_procfs,
|
||||
};
|
||||
|
||||
static void remove_cache_proc_entries(struct cache_detail *cd)
|
||||
{
|
||||
if (cd->u.procfs.proc_ent == NULL)
|
||||
return;
|
||||
if (cd->u.procfs.flush_ent)
|
||||
remove_proc_entry("flush", cd->u.procfs.proc_ent);
|
||||
if (cd->u.procfs.channel_ent)
|
||||
remove_proc_entry("channel", cd->u.procfs.proc_ent);
|
||||
if (cd->u.procfs.content_ent)
|
||||
remove_proc_entry("content", cd->u.procfs.proc_ent);
|
||||
cd->u.procfs.proc_ent = NULL;
|
||||
remove_proc_entry(cd->name, proc_net_rpc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static int create_cache_proc_entries(struct cache_detail *cd)
|
||||
{
|
||||
struct proc_dir_entry *p;
|
||||
|
||||
cd->u.procfs.proc_ent = proc_mkdir(cd->name, proc_net_rpc);
|
||||
if (cd->u.procfs.proc_ent == NULL)
|
||||
goto out_nomem;
|
||||
cd->u.procfs.channel_ent = NULL;
|
||||
cd->u.procfs.content_ent = NULL;
|
||||
|
||||
p = proc_create_data("flush", S_IFREG|S_IRUSR|S_IWUSR,
|
||||
cd->u.procfs.proc_ent,
|
||||
&cache_flush_operations_procfs, cd);
|
||||
cd->u.procfs.flush_ent = p;
|
||||
if (p == NULL)
|
||||
goto out_nomem;
|
||||
|
||||
if (cd->cache_upcall || cd->cache_parse) {
|
||||
p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR,
|
||||
cd->u.procfs.proc_ent,
|
||||
&cache_file_operations_procfs, cd);
|
||||
cd->u.procfs.channel_ent = p;
|
||||
if (p == NULL)
|
||||
goto out_nomem;
|
||||
}
|
||||
if (cd->cache_show) {
|
||||
p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR,
|
||||
cd->u.procfs.proc_ent,
|
||||
&content_file_operations_procfs, cd);
|
||||
cd->u.procfs.content_ent = p;
|
||||
if (p == NULL)
|
||||
goto out_nomem;
|
||||
}
|
||||
return 0;
|
||||
out_nomem:
|
||||
remove_cache_proc_entries(cd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#else /* CONFIG_PROC_FS */
|
||||
static int create_cache_proc_entries(struct cache_detail *cd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int cache_register(struct cache_detail *cd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sunrpc_init_cache_detail(cd);
|
||||
ret = create_cache_proc_entries(cd);
|
||||
if (ret)
|
||||
sunrpc_destroy_cache_detail(cd);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cache_register);
|
||||
|
||||
void cache_unregister(struct cache_detail *cd)
|
||||
{
|
||||
remove_cache_proc_entries(cd);
|
||||
sunrpc_destroy_cache_detail(cd);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cache_unregister);
|
||||
|
||||
static ssize_t cache_read_pipefs(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private;
|
||||
|
||||
return cache_read(filp, buf, count, ppos, cd);
|
||||
}
|
||||
|
||||
static ssize_t cache_write_pipefs(struct file *filp, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private;
|
||||
|
||||
return cache_write(filp, buf, count, ppos, cd);
|
||||
}
|
||||
|
||||
static unsigned int cache_poll_pipefs(struct file *filp, poll_table *wait)
|
||||
{
|
||||
struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private;
|
||||
|
||||
return cache_poll(filp, wait, cd);
|
||||
}
|
||||
|
||||
static int cache_ioctl_pipefs(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct cache_detail *cd = RPC_I(inode)->private;
|
||||
|
||||
return cache_ioctl(inode, filp, cmd, arg, cd);
|
||||
}
|
||||
|
||||
static int cache_open_pipefs(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct cache_detail *cd = RPC_I(inode)->private;
|
||||
|
||||
return cache_open(inode, filp, cd);
|
||||
}
|
||||
|
||||
static int cache_release_pipefs(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct cache_detail *cd = RPC_I(inode)->private;
|
||||
|
||||
return cache_release(inode, filp, cd);
|
||||
}
|
||||
|
||||
const struct file_operations cache_file_operations_pipefs = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.read = cache_read_pipefs,
|
||||
.write = cache_write_pipefs,
|
||||
.poll = cache_poll_pipefs,
|
||||
.ioctl = cache_ioctl_pipefs, /* for FIONREAD */
|
||||
.open = cache_open_pipefs,
|
||||
.release = cache_release_pipefs,
|
||||
};
|
||||
|
||||
static int content_open_pipefs(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct cache_detail *cd = RPC_I(inode)->private;
|
||||
|
||||
return content_open(inode, filp, cd);
|
||||
}
|
||||
|
||||
const struct file_operations content_file_operations_pipefs = {
|
||||
.open = content_open_pipefs,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release_private,
|
||||
};
|
||||
|
||||
static ssize_t read_flush_pipefs(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private;
|
||||
|
||||
return read_flush(filp, buf, count, ppos, cd);
|
||||
}
|
||||
|
||||
static ssize_t write_flush_pipefs(struct file *filp,
|
||||
const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private;
|
||||
|
||||
return write_flush(filp, buf, count, ppos, cd);
|
||||
}
|
||||
|
||||
const struct file_operations cache_flush_operations_pipefs = {
|
||||
.open = nonseekable_open,
|
||||
.read = read_flush_pipefs,
|
||||
.write = write_flush_pipefs,
|
||||
};
|
||||
|
||||
int sunrpc_cache_register_pipefs(struct dentry *parent,
|
||||
const char *name, mode_t umode,
|
||||
struct cache_detail *cd)
|
||||
{
|
||||
struct qstr q;
|
||||
struct dentry *dir;
|
||||
int ret = 0;
|
||||
|
||||
sunrpc_init_cache_detail(cd);
|
||||
q.name = name;
|
||||
q.len = strlen(name);
|
||||
q.hash = full_name_hash(q.name, q.len);
|
||||
dir = rpc_create_cache_dir(parent, &q, umode, cd);
|
||||
if (!IS_ERR(dir))
|
||||
cd->u.pipefs.dir = dir;
|
||||
else {
|
||||
sunrpc_destroy_cache_detail(cd);
|
||||
ret = PTR_ERR(dir);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs);
|
||||
|
||||
void sunrpc_cache_unregister_pipefs(struct cache_detail *cd)
|
||||
{
|
||||
rpc_remove_cache_dir(cd->u.pipefs.dir);
|
||||
cd->u.pipefs.dir = NULL;
|
||||
sunrpc_destroy_cache_detail(cd);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs);
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
@ -97,33 +99,49 @@ static int
|
|||
rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
|
||||
{
|
||||
static uint32_t clntid;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
char name[15];
|
||||
struct qstr q = {
|
||||
.name = name,
|
||||
};
|
||||
int error;
|
||||
|
||||
clnt->cl_vfsmnt = ERR_PTR(-ENOENT);
|
||||
clnt->cl_dentry = ERR_PTR(-ENOENT);
|
||||
clnt->cl_path.mnt = ERR_PTR(-ENOENT);
|
||||
clnt->cl_path.dentry = ERR_PTR(-ENOENT);
|
||||
if (dir_name == NULL)
|
||||
return 0;
|
||||
|
||||
clnt->cl_vfsmnt = rpc_get_mount();
|
||||
if (IS_ERR(clnt->cl_vfsmnt))
|
||||
return PTR_ERR(clnt->cl_vfsmnt);
|
||||
path.mnt = rpc_get_mount();
|
||||
if (IS_ERR(path.mnt))
|
||||
return PTR_ERR(path.mnt);
|
||||
error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &nd);
|
||||
if (error)
|
||||
goto err;
|
||||
|
||||
for (;;) {
|
||||
snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname),
|
||||
"%s/clnt%x", dir_name,
|
||||
(unsigned int)clntid++);
|
||||
clnt->cl_pathname[sizeof(clnt->cl_pathname) - 1] = '\0';
|
||||
clnt->cl_dentry = rpc_mkdir(clnt->cl_pathname, clnt);
|
||||
if (!IS_ERR(clnt->cl_dentry))
|
||||
return 0;
|
||||
error = PTR_ERR(clnt->cl_dentry);
|
||||
q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
q.hash = full_name_hash(q.name, q.len);
|
||||
path.dentry = rpc_create_client_dir(nd.path.dentry, &q, clnt);
|
||||
if (!IS_ERR(path.dentry))
|
||||
break;
|
||||
error = PTR_ERR(path.dentry);
|
||||
if (error != -EEXIST) {
|
||||
printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n",
|
||||
clnt->cl_pathname, error);
|
||||
rpc_put_mount();
|
||||
return error;
|
||||
printk(KERN_INFO "RPC: Couldn't create pipefs entry"
|
||||
" %s/%s, error %d\n",
|
||||
dir_name, name, error);
|
||||
goto err_path_put;
|
||||
}
|
||||
}
|
||||
path_put(&nd.path);
|
||||
clnt->cl_path = path;
|
||||
return 0;
|
||||
err_path_put:
|
||||
path_put(&nd.path);
|
||||
err:
|
||||
rpc_put_mount();
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
|
||||
|
@ -231,8 +249,8 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
|
|||
return clnt;
|
||||
|
||||
out_no_auth:
|
||||
if (!IS_ERR(clnt->cl_dentry)) {
|
||||
rpc_rmdir(clnt->cl_dentry);
|
||||
if (!IS_ERR(clnt->cl_path.dentry)) {
|
||||
rpc_remove_client_dir(clnt->cl_path.dentry);
|
||||
rpc_put_mount();
|
||||
}
|
||||
out_no_path:
|
||||
|
@ -423,8 +441,8 @@ rpc_free_client(struct kref *kref)
|
|||
|
||||
dprintk("RPC: destroying %s client for %s\n",
|
||||
clnt->cl_protname, clnt->cl_server);
|
||||
if (!IS_ERR(clnt->cl_dentry)) {
|
||||
rpc_rmdir(clnt->cl_dentry);
|
||||
if (!IS_ERR(clnt->cl_path.dentry)) {
|
||||
rpc_remove_client_dir(clnt->cl_path.dentry);
|
||||
rpc_put_mount();
|
||||
}
|
||||
if (clnt->cl_parent != clnt) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||
#include <linux/sunrpc/cache.h>
|
||||
|
||||
static struct vfsmount *rpc_mount __read_mostly;
|
||||
static int rpc_mount_count;
|
||||
|
@ -125,7 +126,7 @@ static void
|
|||
rpc_close_pipes(struct inode *inode)
|
||||
{
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
struct rpc_pipe_ops *ops;
|
||||
const struct rpc_pipe_ops *ops;
|
||||
int need_release;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
|
@ -397,67 +398,13 @@ static const struct file_operations rpc_info_operations = {
|
|||
};
|
||||
|
||||
|
||||
/*
|
||||
* We have a single directory with 1 node in it.
|
||||
*/
|
||||
enum {
|
||||
RPCAUTH_Root = 1,
|
||||
RPCAUTH_lockd,
|
||||
RPCAUTH_mount,
|
||||
RPCAUTH_nfs,
|
||||
RPCAUTH_portmap,
|
||||
RPCAUTH_statd,
|
||||
RPCAUTH_nfsd4_cb,
|
||||
RPCAUTH_RootEOF
|
||||
};
|
||||
|
||||
/*
|
||||
* Description of fs contents.
|
||||
*/
|
||||
struct rpc_filelist {
|
||||
char *name;
|
||||
const char *name;
|
||||
const struct file_operations *i_fop;
|
||||
int mode;
|
||||
};
|
||||
|
||||
static struct rpc_filelist files[] = {
|
||||
[RPCAUTH_lockd] = {
|
||||
.name = "lockd",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_mount] = {
|
||||
.name = "mount",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_nfs] = {
|
||||
.name = "nfs",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_portmap] = {
|
||||
.name = "portmap",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_statd] = {
|
||||
.name = "statd",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_nfsd4_cb] = {
|
||||
.name = "nfsd4_cb",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
};
|
||||
|
||||
enum {
|
||||
RPCAUTH_info = 2,
|
||||
RPCAUTH_EOF
|
||||
};
|
||||
|
||||
static struct rpc_filelist authfiles[] = {
|
||||
[RPCAUTH_info] = {
|
||||
.name = "info",
|
||||
.i_fop = &rpc_info_operations,
|
||||
.mode = S_IFREG | S_IRUSR,
|
||||
},
|
||||
umode_t mode;
|
||||
};
|
||||
|
||||
struct vfsmount *rpc_get_mount(void)
|
||||
|
@ -484,39 +431,8 @@ static const struct dentry_operations rpc_dentry_operations = {
|
|||
.d_delete = rpc_delete_dentry,
|
||||
};
|
||||
|
||||
static int
|
||||
rpc_lookup_parent(char *path, struct nameidata *nd)
|
||||
{
|
||||
struct vfsmount *mnt;
|
||||
|
||||
if (path[0] == '\0')
|
||||
return -ENOENT;
|
||||
|
||||
mnt = rpc_get_mount();
|
||||
if (IS_ERR(mnt)) {
|
||||
printk(KERN_WARNING "%s: %s failed to mount "
|
||||
"pseudofilesystem \n", __FILE__, __func__);
|
||||
return PTR_ERR(mnt);
|
||||
}
|
||||
|
||||
if (vfs_path_lookup(mnt->mnt_root, mnt, path, LOOKUP_PARENT, nd)) {
|
||||
printk(KERN_WARNING "%s: %s failed to find path %s\n",
|
||||
__FILE__, __func__, path);
|
||||
rpc_put_mount();
|
||||
return -ENOENT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_release_path(struct nameidata *nd)
|
||||
{
|
||||
path_put(&nd->path);
|
||||
rpc_put_mount();
|
||||
}
|
||||
|
||||
static struct inode *
|
||||
rpc_get_inode(struct super_block *sb, int mode)
|
||||
rpc_get_inode(struct super_block *sb, umode_t mode)
|
||||
{
|
||||
struct inode *inode = new_inode(sb);
|
||||
if (!inode)
|
||||
|
@ -534,212 +450,274 @@ rpc_get_inode(struct super_block *sb, int mode)
|
|||
return inode;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: This probably has races.
|
||||
*/
|
||||
static void rpc_depopulate(struct dentry *parent,
|
||||
unsigned long start, unsigned long eof)
|
||||
{
|
||||
struct inode *dir = parent->d_inode;
|
||||
struct list_head *pos, *next;
|
||||
struct dentry *dentry, *dvec[10];
|
||||
int n = 0;
|
||||
|
||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
|
||||
repeat:
|
||||
spin_lock(&dcache_lock);
|
||||
list_for_each_safe(pos, next, &parent->d_subdirs) {
|
||||
dentry = list_entry(pos, struct dentry, d_u.d_child);
|
||||
if (!dentry->d_inode ||
|
||||
dentry->d_inode->i_ino < start ||
|
||||
dentry->d_inode->i_ino >= eof)
|
||||
continue;
|
||||
spin_lock(&dentry->d_lock);
|
||||
if (!d_unhashed(dentry)) {
|
||||
dget_locked(dentry);
|
||||
__d_drop(dentry);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
dvec[n++] = dentry;
|
||||
if (n == ARRAY_SIZE(dvec))
|
||||
break;
|
||||
} else
|
||||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
if (n) {
|
||||
do {
|
||||
dentry = dvec[--n];
|
||||
if (S_ISREG(dentry->d_inode->i_mode))
|
||||
simple_unlink(dir, dentry);
|
||||
else if (S_ISDIR(dentry->d_inode->i_mode))
|
||||
simple_rmdir(dir, dentry);
|
||||
d_delete(dentry);
|
||||
dput(dentry);
|
||||
} while (n);
|
||||
goto repeat;
|
||||
}
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_populate(struct dentry *parent,
|
||||
struct rpc_filelist *files,
|
||||
int start, int eof)
|
||||
{
|
||||
struct inode *inode, *dir = parent->d_inode;
|
||||
void *private = RPC_I(dir)->private;
|
||||
struct dentry *dentry;
|
||||
int mode, i;
|
||||
|
||||
mutex_lock(&dir->i_mutex);
|
||||
for (i = start; i < eof; i++) {
|
||||
dentry = d_alloc_name(parent, files[i].name);
|
||||
if (!dentry)
|
||||
goto out_bad;
|
||||
dentry->d_op = &rpc_dentry_operations;
|
||||
mode = files[i].mode;
|
||||
inode = rpc_get_inode(dir->i_sb, mode);
|
||||
if (!inode) {
|
||||
dput(dentry);
|
||||
goto out_bad;
|
||||
}
|
||||
inode->i_ino = i;
|
||||
if (files[i].i_fop)
|
||||
inode->i_fop = files[i].i_fop;
|
||||
if (private)
|
||||
rpc_inode_setowner(inode, private);
|
||||
if (S_ISDIR(mode))
|
||||
inc_nlink(dir);
|
||||
d_add(dentry, inode);
|
||||
fsnotify_create(dir, dentry);
|
||||
}
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
return 0;
|
||||
out_bad:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
printk(KERN_WARNING "%s: %s failed to populate directory %s\n",
|
||||
__FILE__, __func__, parent->d_name.name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int
|
||||
__rpc_mkdir(struct inode *dir, struct dentry *dentry)
|
||||
static int __rpc_create_common(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode,
|
||||
const struct file_operations *i_fop,
|
||||
void *private)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO);
|
||||
BUG_ON(!d_unhashed(dentry));
|
||||
inode = rpc_get_inode(dir->i_sb, mode);
|
||||
if (!inode)
|
||||
goto out_err;
|
||||
inode->i_ino = iunique(dir->i_sb, 100);
|
||||
d_instantiate(dentry, inode);
|
||||
inc_nlink(dir);
|
||||
fsnotify_mkdir(dir, dentry);
|
||||
if (i_fop)
|
||||
inode->i_fop = i_fop;
|
||||
if (private)
|
||||
rpc_inode_setowner(inode, private);
|
||||
d_add(dentry, inode);
|
||||
return 0;
|
||||
out_err:
|
||||
printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
|
||||
__FILE__, __func__, dentry->d_name.name);
|
||||
dput(dentry);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int
|
||||
__rpc_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
static int __rpc_create(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode,
|
||||
const struct file_operations *i_fop,
|
||||
void *private)
|
||||
{
|
||||
int error;
|
||||
error = simple_rmdir(dir, dentry);
|
||||
if (!error)
|
||||
d_delete(dentry);
|
||||
return error;
|
||||
int err;
|
||||
|
||||
err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private);
|
||||
if (err)
|
||||
return err;
|
||||
fsnotify_create(dir, dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dentry *
|
||||
rpc_lookup_create(struct dentry *parent, const char *name, int len, int exclusive)
|
||||
static int __rpc_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode,
|
||||
const struct file_operations *i_fop,
|
||||
void *private)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private);
|
||||
if (err)
|
||||
return err;
|
||||
inc_nlink(dir);
|
||||
fsnotify_mkdir(dir, dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode,
|
||||
const struct file_operations *i_fop,
|
||||
void *private,
|
||||
const struct rpc_pipe_ops *ops,
|
||||
int flags)
|
||||
{
|
||||
struct rpc_inode *rpci;
|
||||
int err;
|
||||
|
||||
err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private);
|
||||
if (err)
|
||||
return err;
|
||||
rpci = RPC_I(dentry->d_inode);
|
||||
rpci->nkern_readwriters = 1;
|
||||
rpci->private = private;
|
||||
rpci->flags = flags;
|
||||
rpci->ops = ops;
|
||||
fsnotify_create(dir, dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int ret;
|
||||
|
||||
dget(dentry);
|
||||
ret = simple_rmdir(dir, dentry);
|
||||
d_delete(dentry);
|
||||
dput(dentry);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int ret;
|
||||
|
||||
dget(dentry);
|
||||
ret = simple_unlink(dir, dentry);
|
||||
d_delete(dentry);
|
||||
dput(dentry);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
|
||||
rpci->nkern_readwriters--;
|
||||
if (rpci->nkern_readwriters != 0)
|
||||
return 0;
|
||||
rpc_close_pipes(inode);
|
||||
return __rpc_unlink(dir, dentry);
|
||||
}
|
||||
|
||||
static struct dentry *__rpc_lookup_create(struct dentry *parent,
|
||||
struct qstr *name)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
|
||||
dentry = d_lookup(parent, name);
|
||||
if (!dentry) {
|
||||
dentry = d_alloc(parent, name);
|
||||
if (!dentry) {
|
||||
dentry = ERR_PTR(-ENOMEM);
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
if (!dentry->d_inode)
|
||||
dentry->d_op = &rpc_dentry_operations;
|
||||
out_err:
|
||||
return dentry;
|
||||
}
|
||||
|
||||
static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
|
||||
struct qstr *name)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
|
||||
dentry = __rpc_lookup_create(parent, name);
|
||||
if (dentry->d_inode == NULL)
|
||||
return dentry;
|
||||
dput(dentry);
|
||||
return ERR_PTR(-EEXIST);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: This probably has races.
|
||||
*/
|
||||
static void __rpc_depopulate(struct dentry *parent,
|
||||
const struct rpc_filelist *files,
|
||||
int start, int eof)
|
||||
{
|
||||
struct inode *dir = parent->d_inode;
|
||||
struct dentry *dentry;
|
||||
struct qstr name;
|
||||
int i;
|
||||
|
||||
for (i = start; i < eof; i++) {
|
||||
name.name = files[i].name;
|
||||
name.len = strlen(files[i].name);
|
||||
name.hash = full_name_hash(name.name, name.len);
|
||||
dentry = d_lookup(parent, &name);
|
||||
|
||||
if (dentry == NULL)
|
||||
continue;
|
||||
if (dentry->d_inode == NULL)
|
||||
goto next;
|
||||
switch (dentry->d_inode->i_mode & S_IFMT) {
|
||||
default:
|
||||
BUG();
|
||||
case S_IFREG:
|
||||
__rpc_unlink(dir, dentry);
|
||||
break;
|
||||
case S_IFDIR:
|
||||
__rpc_rmdir(dir, dentry);
|
||||
}
|
||||
next:
|
||||
dput(dentry);
|
||||
}
|
||||
}
|
||||
|
||||
static void rpc_depopulate(struct dentry *parent,
|
||||
const struct rpc_filelist *files,
|
||||
int start, int eof)
|
||||
{
|
||||
struct inode *dir = parent->d_inode;
|
||||
|
||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
|
||||
__rpc_depopulate(parent, files, start, eof);
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
}
|
||||
|
||||
static int rpc_populate(struct dentry *parent,
|
||||
const struct rpc_filelist *files,
|
||||
int start, int eof,
|
||||
void *private)
|
||||
{
|
||||
struct inode *dir = parent->d_inode;
|
||||
struct dentry *dentry;
|
||||
int i, err;
|
||||
|
||||
mutex_lock(&dir->i_mutex);
|
||||
for (i = start; i < eof; i++) {
|
||||
struct qstr q;
|
||||
|
||||
q.name = files[i].name;
|
||||
q.len = strlen(files[i].name);
|
||||
q.hash = full_name_hash(q.name, q.len);
|
||||
dentry = __rpc_lookup_create_exclusive(parent, &q);
|
||||
err = PTR_ERR(dentry);
|
||||
if (IS_ERR(dentry))
|
||||
goto out_bad;
|
||||
switch (files[i].mode & S_IFMT) {
|
||||
default:
|
||||
BUG();
|
||||
case S_IFREG:
|
||||
err = __rpc_create(dir, dentry,
|
||||
files[i].mode,
|
||||
files[i].i_fop,
|
||||
private);
|
||||
break;
|
||||
case S_IFDIR:
|
||||
err = __rpc_mkdir(dir, dentry,
|
||||
files[i].mode,
|
||||
NULL,
|
||||
private);
|
||||
}
|
||||
if (err != 0)
|
||||
goto out_bad;
|
||||
}
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
return 0;
|
||||
out_bad:
|
||||
__rpc_depopulate(parent, files, start, eof);
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
printk(KERN_WARNING "%s: %s failed to populate directory %s\n",
|
||||
__FILE__, __func__, parent->d_name.name);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct dentry *rpc_mkdir_populate(struct dentry *parent,
|
||||
struct qstr *name, umode_t mode, void *private,
|
||||
int (*populate)(struct dentry *, void *), void *args_populate)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct inode *dir = parent->d_inode;
|
||||
int error;
|
||||
|
||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
dentry = lookup_one_len(name, parent, len);
|
||||
dentry = __rpc_lookup_create_exclusive(parent, name);
|
||||
if (IS_ERR(dentry))
|
||||
goto out;
|
||||
error = __rpc_mkdir(dir, dentry, mode, NULL, private);
|
||||
if (error != 0)
|
||||
goto out_err;
|
||||
if (!dentry->d_inode)
|
||||
dentry->d_op = &rpc_dentry_operations;
|
||||
else if (exclusive) {
|
||||
dput(dentry);
|
||||
dentry = ERR_PTR(-EEXIST);
|
||||
goto out_err;
|
||||
if (populate != NULL) {
|
||||
error = populate(dentry, args_populate);
|
||||
if (error)
|
||||
goto err_rmdir;
|
||||
}
|
||||
return dentry;
|
||||
out_err:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
return dentry;
|
||||
}
|
||||
|
||||
static struct dentry *
|
||||
rpc_lookup_negative(char *path, struct nameidata *nd)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
int error;
|
||||
|
||||
if ((error = rpc_lookup_parent(path, nd)) != 0)
|
||||
return ERR_PTR(error);
|
||||
dentry = rpc_lookup_create(nd->path.dentry, nd->last.name, nd->last.len,
|
||||
1);
|
||||
if (IS_ERR(dentry))
|
||||
rpc_release_path(nd);
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_mkdir - Create a new directory in rpc_pipefs
|
||||
* @path: path from the rpc_pipefs root to the 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().
|
||||
*/
|
||||
struct dentry *
|
||||
rpc_mkdir(char *path, struct rpc_clnt *rpc_client)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct dentry *dentry;
|
||||
struct inode *dir;
|
||||
int error;
|
||||
|
||||
dentry = rpc_lookup_negative(path, &nd);
|
||||
if (IS_ERR(dentry))
|
||||
return dentry;
|
||||
dir = nd.path.dentry->d_inode;
|
||||
if ((error = __rpc_mkdir(dir, dentry)) != 0)
|
||||
goto err_dput;
|
||||
RPC_I(dentry->d_inode)->private = rpc_client;
|
||||
error = rpc_populate(dentry, authfiles,
|
||||
RPCAUTH_info, RPCAUTH_EOF);
|
||||
if (error)
|
||||
goto err_depopulate;
|
||||
dget(dentry);
|
||||
out:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
rpc_release_path(&nd);
|
||||
return dentry;
|
||||
err_depopulate:
|
||||
rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF);
|
||||
err_rmdir:
|
||||
__rpc_rmdir(dir, dentry);
|
||||
err_dput:
|
||||
dput(dentry);
|
||||
printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n",
|
||||
__FILE__, __func__, path, error);
|
||||
out_err:
|
||||
dentry = ERR_PTR(error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_rmdir - Remove a directory created with rpc_mkdir()
|
||||
* @dentry: directory to remove
|
||||
*/
|
||||
int
|
||||
rpc_rmdir(struct dentry *dentry)
|
||||
static int rpc_rmdir_depopulate(struct dentry *dentry,
|
||||
void (*depopulate)(struct dentry *))
|
||||
{
|
||||
struct dentry *parent;
|
||||
struct inode *dir;
|
||||
|
@ -748,9 +726,9 @@ rpc_rmdir(struct dentry *dentry)
|
|||
parent = dget_parent(dentry);
|
||||
dir = parent->d_inode;
|
||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF);
|
||||
if (depopulate != NULL)
|
||||
depopulate(dentry);
|
||||
error = __rpc_rmdir(dir, dentry);
|
||||
dput(dentry);
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
dput(parent);
|
||||
return error;
|
||||
|
@ -776,50 +754,54 @@ rpc_rmdir(struct dentry *dentry)
|
|||
* The @private argument passed here will be available to all these methods
|
||||
* from the file pointer, via RPC_I(file->f_dentry->d_inode)->private.
|
||||
*/
|
||||
struct dentry *
|
||||
rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags)
|
||||
struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,
|
||||
void *private, const struct rpc_pipe_ops *ops,
|
||||
int flags)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct inode *dir, *inode;
|
||||
struct rpc_inode *rpci;
|
||||
struct inode *dir = parent->d_inode;
|
||||
umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR;
|
||||
struct qstr q;
|
||||
int err;
|
||||
|
||||
dentry = rpc_lookup_create(parent, name, strlen(name), 0);
|
||||
if (ops->upcall == NULL)
|
||||
umode &= ~S_IRUGO;
|
||||
if (ops->downcall == NULL)
|
||||
umode &= ~S_IWUGO;
|
||||
|
||||
q.name = name;
|
||||
q.len = strlen(name);
|
||||
q.hash = full_name_hash(q.name, q.len),
|
||||
|
||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
dentry = __rpc_lookup_create(parent, &q);
|
||||
if (IS_ERR(dentry))
|
||||
return dentry;
|
||||
dir = parent->d_inode;
|
||||
goto out;
|
||||
if (dentry->d_inode) {
|
||||
rpci = RPC_I(dentry->d_inode);
|
||||
struct rpc_inode *rpci = RPC_I(dentry->d_inode);
|
||||
if (rpci->private != private ||
|
||||
rpci->ops != ops ||
|
||||
rpci->flags != flags) {
|
||||
dput (dentry);
|
||||
dentry = ERR_PTR(-EBUSY);
|
||||
err = -EBUSY;
|
||||
goto out_err;
|
||||
}
|
||||
rpci->nkern_readwriters++;
|
||||
goto out;
|
||||
}
|
||||
inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR);
|
||||
if (!inode)
|
||||
goto err_dput;
|
||||
inode->i_ino = iunique(dir->i_sb, 100);
|
||||
inode->i_fop = &rpc_pipe_fops;
|
||||
d_instantiate(dentry, inode);
|
||||
rpci = RPC_I(inode);
|
||||
rpci->private = private;
|
||||
rpci->flags = flags;
|
||||
rpci->ops = ops;
|
||||
rpci->nkern_readwriters = 1;
|
||||
fsnotify_create(dir, dentry);
|
||||
dget(dentry);
|
||||
|
||||
err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops,
|
||||
private, ops, flags);
|
||||
if (err)
|
||||
goto out_err;
|
||||
out:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
return dentry;
|
||||
err_dput:
|
||||
dput(dentry);
|
||||
dentry = ERR_PTR(-ENOMEM);
|
||||
out_err:
|
||||
dentry = ERR_PTR(err);
|
||||
printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n",
|
||||
__FILE__, __func__, parent->d_name.name, name,
|
||||
-ENOMEM);
|
||||
err);
|
||||
goto out;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_mkpipe);
|
||||
|
@ -842,19 +824,107 @@ rpc_unlink(struct dentry *dentry)
|
|||
parent = dget_parent(dentry);
|
||||
dir = parent->d_inode;
|
||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
if (--RPC_I(dentry->d_inode)->nkern_readwriters == 0) {
|
||||
rpc_close_pipes(dentry->d_inode);
|
||||
error = simple_unlink(dir, dentry);
|
||||
if (!error)
|
||||
d_delete(dentry);
|
||||
}
|
||||
dput(dentry);
|
||||
error = __rpc_rmpipe(dir, dentry);
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
dput(parent);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_unlink);
|
||||
|
||||
enum {
|
||||
RPCAUTH_info,
|
||||
RPCAUTH_EOF
|
||||
};
|
||||
|
||||
static const struct rpc_filelist authfiles[] = {
|
||||
[RPCAUTH_info] = {
|
||||
.name = "info",
|
||||
.i_fop = &rpc_info_operations,
|
||||
.mode = S_IFREG | S_IRUSR,
|
||||
},
|
||||
};
|
||||
|
||||
static int rpc_clntdir_populate(struct dentry *dentry, void *private)
|
||||
{
|
||||
return rpc_populate(dentry,
|
||||
authfiles, RPCAUTH_info, RPCAUTH_EOF,
|
||||
private);
|
||||
}
|
||||
|
||||
static void rpc_clntdir_depopulate(struct dentry *dentry)
|
||||
{
|
||||
rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF);
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs
|
||||
* @path: path from the rpc_pipefs root to the 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().
|
||||
*/
|
||||
struct dentry *rpc_create_client_dir(struct dentry *dentry,
|
||||
struct qstr *name,
|
||||
struct rpc_clnt *rpc_client)
|
||||
{
|
||||
return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL,
|
||||
rpc_clntdir_populate, rpc_client);
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
|
||||
* @dentry: directory to remove
|
||||
*/
|
||||
int rpc_remove_client_dir(struct dentry *dentry)
|
||||
{
|
||||
return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate);
|
||||
}
|
||||
|
||||
static const struct rpc_filelist cache_pipefs_files[3] = {
|
||||
[0] = {
|
||||
.name = "channel",
|
||||
.i_fop = &cache_file_operations_pipefs,
|
||||
.mode = S_IFIFO|S_IRUSR|S_IWUSR,
|
||||
},
|
||||
[1] = {
|
||||
.name = "content",
|
||||
.i_fop = &content_file_operations_pipefs,
|
||||
.mode = S_IFREG|S_IRUSR,
|
||||
},
|
||||
[2] = {
|
||||
.name = "flush",
|
||||
.i_fop = &cache_flush_operations_pipefs,
|
||||
.mode = S_IFREG|S_IRUSR|S_IWUSR,
|
||||
},
|
||||
};
|
||||
|
||||
static int rpc_cachedir_populate(struct dentry *dentry, void *private)
|
||||
{
|
||||
return rpc_populate(dentry,
|
||||
cache_pipefs_files, 0, 3,
|
||||
private);
|
||||
}
|
||||
|
||||
static void rpc_cachedir_depopulate(struct dentry *dentry)
|
||||
{
|
||||
rpc_depopulate(dentry, cache_pipefs_files, 0, 3);
|
||||
}
|
||||
|
||||
struct dentry *rpc_create_cache_dir(struct dentry *parent, struct qstr *name,
|
||||
mode_t umode, struct cache_detail *cd)
|
||||
{
|
||||
return rpc_mkdir_populate(parent, name, umode, NULL,
|
||||
rpc_cachedir_populate, cd);
|
||||
}
|
||||
|
||||
void rpc_remove_cache_dir(struct dentry *dentry)
|
||||
{
|
||||
rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate);
|
||||
}
|
||||
|
||||
/*
|
||||
* populate the filesystem
|
||||
*/
|
||||
|
@ -866,6 +936,46 @@ static struct super_operations s_ops = {
|
|||
|
||||
#define RPCAUTH_GSSMAGIC 0x67596969
|
||||
|
||||
/*
|
||||
* 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_RootEOF
|
||||
};
|
||||
|
||||
static const struct rpc_filelist files[] = {
|
||||
[RPCAUTH_lockd] = {
|
||||
.name = "lockd",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_mount] = {
|
||||
.name = "mount",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_nfs] = {
|
||||
.name = "nfs",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_portmap] = {
|
||||
.name = "portmap",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_statd] = {
|
||||
.name = "statd",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_nfsd4_cb] = {
|
||||
.name = "nfsd4_cb",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
rpc_fill_super(struct super_block *sb, void *data, int silent)
|
||||
{
|
||||
|
@ -886,7 +996,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
|
|||
iput(inode);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (rpc_populate(root, files, RPCAUTH_Root + 1, RPCAUTH_RootEOF))
|
||||
if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
|
||||
goto out;
|
||||
sb->s_root = root;
|
||||
return 0;
|
||||
|
|
|
@ -171,6 +171,11 @@ static void ip_map_request(struct cache_detail *cd,
|
|||
(*bpp)[-1] = '\n';
|
||||
}
|
||||
|
||||
static int ip_map_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall(cd, h, ip_map_request);
|
||||
}
|
||||
|
||||
static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
|
||||
static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
|
||||
|
||||
|
@ -289,7 +294,7 @@ struct cache_detail ip_map_cache = {
|
|||
.hash_table = ip_table,
|
||||
.name = "auth.unix.ip",
|
||||
.cache_put = ip_map_put,
|
||||
.cache_request = ip_map_request,
|
||||
.cache_upcall = ip_map_upcall,
|
||||
.cache_parse = ip_map_parse,
|
||||
.cache_show = ip_map_show,
|
||||
.match = ip_map_match,
|
||||
|
@ -523,6 +528,11 @@ static void unix_gid_request(struct cache_detail *cd,
|
|||
(*bpp)[-1] = '\n';
|
||||
}
|
||||
|
||||
static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request);
|
||||
}
|
||||
|
||||
static struct unix_gid *unix_gid_lookup(uid_t uid);
|
||||
extern struct cache_detail unix_gid_cache;
|
||||
|
||||
|
@ -622,7 +632,7 @@ struct cache_detail unix_gid_cache = {
|
|||
.hash_table = gid_table,
|
||||
.name = "auth.unix.gid",
|
||||
.cache_put = unix_gid_put,
|
||||
.cache_request = unix_gid_request,
|
||||
.cache_upcall = unix_gid_upcall,
|
||||
.cache_parse = unix_gid_parse,
|
||||
.cache_show = unix_gid_show,
|
||||
.match = unix_gid_match,
|
||||
|
|
Загрузка…
Ссылка в новой задаче