Merge branch 'sunrpc_cache-for-2.6.32' into nfs-for-2.6.32
This commit is contained in:
@@ -101,7 +101,7 @@ static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
|
|||||||
|
|
||||||
static unsigned int fnvhash32(const void *, size_t);
|
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,
|
.upcall = idmap_pipe_upcall,
|
||||||
.downcall = idmap_pipe_downcall,
|
.downcall = idmap_pipe_downcall,
|
||||||
.destroy_msg = idmap_pipe_destroy_msg,
|
.destroy_msg = idmap_pipe_destroy_msg,
|
||||||
@@ -119,8 +119,8 @@ nfs_idmap_new(struct nfs_client *clp)
|
|||||||
if (idmap == NULL)
|
if (idmap == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap",
|
idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry,
|
||||||
idmap, &idmap_upcall_ops, 0);
|
"idmap", idmap, &idmap_upcall_ops, 0);
|
||||||
if (IS_ERR(idmap->idmap_dentry)) {
|
if (IS_ERR(idmap->idmap_dentry)) {
|
||||||
error = PTR_ERR(idmap->idmap_dentry);
|
error = PTR_ERR(idmap->idmap_dentry);
|
||||||
kfree(idmap);
|
kfree(idmap);
|
||||||
|
@@ -85,6 +85,11 @@ static void expkey_request(struct cache_detail *cd,
|
|||||||
(*bpp)[-1] = '\n';
|
(*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_update(struct svc_expkey *new, struct svc_expkey *old);
|
||||||
static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
|
static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
|
||||||
static struct cache_detail svc_expkey_cache;
|
static struct cache_detail svc_expkey_cache;
|
||||||
@@ -259,7 +264,7 @@ static struct cache_detail svc_expkey_cache = {
|
|||||||
.hash_table = expkey_table,
|
.hash_table = expkey_table,
|
||||||
.name = "nfsd.fh",
|
.name = "nfsd.fh",
|
||||||
.cache_put = expkey_put,
|
.cache_put = expkey_put,
|
||||||
.cache_request = expkey_request,
|
.cache_upcall = expkey_upcall,
|
||||||
.cache_parse = expkey_parse,
|
.cache_parse = expkey_parse,
|
||||||
.cache_show = expkey_show,
|
.cache_show = expkey_show,
|
||||||
.match = expkey_match,
|
.match = expkey_match,
|
||||||
@@ -355,6 +360,11 @@ static void svc_export_request(struct cache_detail *cd,
|
|||||||
(*bpp)[-1] = '\n';
|
(*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,
|
static struct svc_export *svc_export_update(struct svc_export *new,
|
||||||
struct svc_export *old);
|
struct svc_export *old);
|
||||||
static struct svc_export *svc_export_lookup(struct svc_export *);
|
static struct svc_export *svc_export_lookup(struct svc_export *);
|
||||||
@@ -724,7 +734,7 @@ struct cache_detail svc_export_cache = {
|
|||||||
.hash_table = export_table,
|
.hash_table = export_table,
|
||||||
.name = "nfsd.export",
|
.name = "nfsd.export",
|
||||||
.cache_put = svc_export_put,
|
.cache_put = svc_export_put,
|
||||||
.cache_request = svc_export_request,
|
.cache_upcall = svc_export_upcall,
|
||||||
.cache_parse = svc_export_parse,
|
.cache_parse = svc_export_parse,
|
||||||
.cache_show = svc_export_show,
|
.cache_show = svc_export_show,
|
||||||
.match = svc_export_match,
|
.match = svc_export_match,
|
||||||
|
@@ -145,6 +145,12 @@ idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
|
|||||||
(*bpp)[-1] = '\n';
|
(*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
|
static int
|
||||||
idtoname_match(struct cache_head *ca, struct cache_head *cb)
|
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
|
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",
|
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,
|
.hash_table = idtoname_table,
|
||||||
.name = "nfs4.idtoname",
|
.name = "nfs4.idtoname",
|
||||||
.cache_put = ent_put,
|
.cache_put = ent_put,
|
||||||
.cache_request = idtoname_request,
|
.cache_upcall = idtoname_upcall,
|
||||||
.cache_parse = idtoname_parse,
|
.cache_parse = idtoname_parse,
|
||||||
.cache_show = idtoname_show,
|
.cache_show = idtoname_show,
|
||||||
.warn_no_listener = warn_no_idmapd,
|
.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';
|
(*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
|
static int
|
||||||
nametoid_match(struct cache_head *ca, struct cache_head *cb)
|
nametoid_match(struct cache_head *ca, struct cache_head *cb)
|
||||||
{
|
{
|
||||||
@@ -363,7 +375,7 @@ static struct cache_detail nametoid_cache = {
|
|||||||
.hash_table = nametoid_table,
|
.hash_table = nametoid_table,
|
||||||
.name = "nfs4.nametoid",
|
.name = "nfs4.nametoid",
|
||||||
.cache_put = ent_put,
|
.cache_put = ent_put,
|
||||||
.cache_request = nametoid_request,
|
.cache_upcall = nametoid_upcall,
|
||||||
.cache_parse = nametoid_parse,
|
.cache_parse = nametoid_parse,
|
||||||
.cache_show = nametoid_show,
|
.cache_show = nametoid_show,
|
||||||
.warn_no_listener = warn_no_idmapd,
|
.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 */
|
#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 cache_detail {
|
||||||
struct module * owner;
|
struct module * owner;
|
||||||
int hash_size;
|
int hash_size;
|
||||||
@@ -70,15 +79,17 @@ struct cache_detail {
|
|||||||
char *name;
|
char *name;
|
||||||
void (*cache_put)(struct kref *);
|
void (*cache_put)(struct kref *);
|
||||||
|
|
||||||
void (*cache_request)(struct cache_detail *cd,
|
int (*cache_upcall)(struct cache_detail *,
|
||||||
struct cache_head *h,
|
struct cache_head *);
|
||||||
char **bpp, int *blen);
|
|
||||||
int (*cache_parse)(struct cache_detail *,
|
int (*cache_parse)(struct cache_detail *,
|
||||||
char *buf, int len);
|
char *buf, int len);
|
||||||
|
|
||||||
int (*cache_show)(struct seq_file *m,
|
int (*cache_show)(struct seq_file *m,
|
||||||
struct cache_detail *cd,
|
struct cache_detail *cd,
|
||||||
struct cache_head *h);
|
struct cache_head *h);
|
||||||
|
void (*warn_no_listener)(struct cache_detail *cd,
|
||||||
|
int has_died);
|
||||||
|
|
||||||
struct cache_head * (*alloc)(void);
|
struct cache_head * (*alloc)(void);
|
||||||
int (*match)(struct cache_head *orig, struct cache_head *new);
|
int (*match)(struct cache_head *orig, struct cache_head *new);
|
||||||
@@ -96,13 +107,15 @@ struct cache_detail {
|
|||||||
|
|
||||||
/* fields for communication over channel */
|
/* fields for communication over channel */
|
||||||
struct list_head queue;
|
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 */
|
atomic_t readers; /* how many time is /chennel open */
|
||||||
time_t last_close; /* if no readers, when did last close */
|
time_t last_close; /* if no readers, when did last close */
|
||||||
time_t last_warn; /* when we last warned about no readers */
|
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 *
|
extern struct cache_head *
|
||||||
sunrpc_cache_lookup(struct cache_detail *detail,
|
sunrpc_cache_lookup(struct cache_detail *detail,
|
||||||
struct cache_head *key, int hash);
|
struct cache_head *key, int hash);
|
||||||
@@ -134,6 +151,13 @@ extern struct cache_head *
|
|||||||
sunrpc_cache_update(struct cache_detail *detail,
|
sunrpc_cache_update(struct cache_detail *detail,
|
||||||
struct cache_head *new, struct cache_head *old, int hash);
|
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);
|
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 int cache_register(struct cache_detail *cd);
|
||||||
extern void cache_unregister(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_add(char **bpp, int *lp, char *str);
|
||||||
extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
|
extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
|
||||||
extern int qword_get(char **bpp, char *dest, int bufsize);
|
extern int qword_get(char **bpp, char *dest, int bufsize);
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include <linux/sunrpc/xdr.h>
|
#include <linux/sunrpc/xdr.h>
|
||||||
#include <linux/sunrpc/timer.h>
|
#include <linux/sunrpc/timer.h>
|
||||||
#include <asm/signal.h>
|
#include <asm/signal.h>
|
||||||
|
#include <linux/path.h>
|
||||||
|
|
||||||
struct rpc_inode;
|
struct rpc_inode;
|
||||||
|
|
||||||
@@ -54,9 +55,7 @@ struct rpc_clnt {
|
|||||||
|
|
||||||
int cl_nodelen; /* nodename length */
|
int cl_nodelen; /* nodename length */
|
||||||
char cl_nodename[UNX_MAXNODENAME];
|
char cl_nodename[UNX_MAXNODENAME];
|
||||||
char cl_pathname[30];/* Path in rpc_pipe_fs */
|
struct path cl_path;
|
||||||
struct vfsmount * cl_vfsmnt;
|
|
||||||
struct dentry * cl_dentry; /* inode */
|
|
||||||
struct rpc_clnt * cl_parent; /* Points to parent of clones */
|
struct rpc_clnt * cl_parent; /* Points to parent of clones */
|
||||||
struct rpc_rtt cl_rtt_default;
|
struct rpc_rtt cl_rtt_default;
|
||||||
struct rpc_timeout cl_timeout_default;
|
struct rpc_timeout cl_timeout_default;
|
||||||
|
@@ -32,8 +32,8 @@ struct rpc_inode {
|
|||||||
wait_queue_head_t waitq;
|
wait_queue_head_t waitq;
|
||||||
#define RPC_PIPE_WAIT_FOR_OPEN 1
|
#define RPC_PIPE_WAIT_FOR_OPEN 1
|
||||||
int flags;
|
int flags;
|
||||||
struct rpc_pipe_ops *ops;
|
|
||||||
struct delayed_work queue_timeout;
|
struct delayed_work queue_timeout;
|
||||||
|
const struct rpc_pipe_ops *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct rpc_inode *
|
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 int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
|
||||||
|
|
||||||
extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
|
struct rpc_clnt;
|
||||||
extern int rpc_rmdir(struct dentry *);
|
extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *);
|
||||||
extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, struct rpc_pipe_ops *, int flags);
|
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 int rpc_unlink(struct dentry *);
|
||||||
extern struct vfsmount *rpc_get_mount(void);
|
extern struct vfsmount *rpc_get_mount(void);
|
||||||
extern void rpc_put_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 DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
|
||||||
|
|
||||||
static void gss_free_ctx(struct gss_cl_ctx *);
|
static void gss_free_ctx(struct gss_cl_ctx *);
|
||||||
static struct rpc_pipe_ops gss_upcall_ops_v0;
|
static const 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_v1;
|
||||||
|
|
||||||
static inline struct gss_cl_ctx *
|
static inline struct gss_cl_ctx *
|
||||||
gss_get_ctx(struct gss_cl_ctx *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
|
* that we supported only the old pipe. So we instead create
|
||||||
* the new pipe first.
|
* the new pipe first.
|
||||||
*/
|
*/
|
||||||
gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_dentry,
|
gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_path.dentry,
|
||||||
"gssd",
|
"gssd",
|
||||||
clnt, &gss_upcall_ops_v1,
|
clnt, &gss_upcall_ops_v1,
|
||||||
RPC_PIPE_WAIT_FOR_OPEN);
|
RPC_PIPE_WAIT_FOR_OPEN);
|
||||||
@@ -786,7 +786,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
|
|||||||
goto err_put_mech;
|
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,
|
gss_auth->mech->gm_name,
|
||||||
clnt, &gss_upcall_ops_v0,
|
clnt, &gss_upcall_ops_v0,
|
||||||
RPC_PIPE_WAIT_FOR_OPEN);
|
RPC_PIPE_WAIT_FOR_OPEN);
|
||||||
@@ -1507,7 +1507,7 @@ static const struct rpc_credops gss_nullops = {
|
|||||||
.crunwrap_resp = gss_unwrap_resp,
|
.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,
|
.upcall = gss_pipe_upcall,
|
||||||
.downcall = gss_pipe_downcall,
|
.downcall = gss_pipe_downcall,
|
||||||
.destroy_msg = gss_pipe_destroy_msg,
|
.destroy_msg = gss_pipe_destroy_msg,
|
||||||
@@ -1515,7 +1515,7 @@ static struct rpc_pipe_ops gss_upcall_ops_v0 = {
|
|||||||
.release_pipe = gss_pipe_release,
|
.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,
|
.upcall = gss_pipe_upcall,
|
||||||
.downcall = gss_pipe_downcall,
|
.downcall = gss_pipe_downcall,
|
||||||
.destroy_msg = gss_pipe_destroy_msg,
|
.destroy_msg = gss_pipe_destroy_msg,
|
||||||
|
@@ -181,6 +181,11 @@ static void rsi_request(struct cache_detail *cd,
|
|||||||
(*bpp)[-1] = '\n';
|
(*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,
|
static int rsi_parse(struct cache_detail *cd,
|
||||||
char *mesg, int mlen)
|
char *mesg, int mlen)
|
||||||
@@ -270,7 +275,7 @@ static struct cache_detail rsi_cache = {
|
|||||||
.hash_table = rsi_table,
|
.hash_table = rsi_table,
|
||||||
.name = "auth.rpcsec.init",
|
.name = "auth.rpcsec.init",
|
||||||
.cache_put = rsi_put,
|
.cache_put = rsi_put,
|
||||||
.cache_request = rsi_request,
|
.cache_upcall = rsi_upcall,
|
||||||
.cache_parse = rsi_parse,
|
.cache_parse = rsi_parse,
|
||||||
.match = rsi_match,
|
.match = rsi_match,
|
||||||
.init = rsi_init,
|
.init = rsi_init,
|
||||||
|
@@ -27,10 +27,12 @@
|
|||||||
#include <linux/net.h>
|
#include <linux/net.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/pagemap.h>
|
||||||
#include <asm/ioctls.h>
|
#include <asm/ioctls.h>
|
||||||
#include <linux/sunrpc/types.h>
|
#include <linux/sunrpc/types.h>
|
||||||
#include <linux/sunrpc/cache.h>
|
#include <linux/sunrpc/cache.h>
|
||||||
#include <linux/sunrpc/stats.h>
|
#include <linux/sunrpc/stats.h>
|
||||||
|
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||||
|
|
||||||
#define RPCDBG_FACILITY RPCDBG_CACHE
|
#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);
|
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
|
* This is the generic cache management routine for all
|
||||||
* the authentication caches.
|
* the authentication caches.
|
||||||
@@ -284,76 +292,11 @@ static DEFINE_SPINLOCK(cache_list_lock);
|
|||||||
static struct cache_detail *current_detail;
|
static struct cache_detail *current_detail;
|
||||||
static int current_index;
|
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 void do_cache_clean(struct work_struct *work);
|
||||||
static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean);
|
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);
|
rwlock_init(&cd->hash_lock);
|
||||||
INIT_LIST_HEAD(&cd->queue);
|
INIT_LIST_HEAD(&cd->queue);
|
||||||
spin_lock(&cache_list_lock);
|
spin_lock(&cache_list_lock);
|
||||||
@@ -367,11 +310,9 @@ int cache_register(struct cache_detail *cd)
|
|||||||
|
|
||||||
/* start the cleaning process */
|
/* start the cleaning process */
|
||||||
schedule_delayed_work(&cache_cleaner, 0);
|
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);
|
cache_purge(cd);
|
||||||
spin_lock(&cache_list_lock);
|
spin_lock(&cache_list_lock);
|
||||||
@@ -386,7 +327,6 @@ void cache_unregister(struct cache_detail *cd)
|
|||||||
list_del_init(&cd->others);
|
list_del_init(&cd->others);
|
||||||
write_unlock(&cd->hash_lock);
|
write_unlock(&cd->hash_lock);
|
||||||
spin_unlock(&cache_list_lock);
|
spin_unlock(&cache_list_lock);
|
||||||
remove_cache_proc_entries(cd);
|
|
||||||
if (list_empty(&cache_list)) {
|
if (list_empty(&cache_list)) {
|
||||||
/* module must be being unloaded so its safe to kill the worker */
|
/* module must be being unloaded so its safe to kill the worker */
|
||||||
cancel_delayed_work_sync(&cache_cleaner);
|
cancel_delayed_work_sync(&cache_cleaner);
|
||||||
@@ -395,7 +335,6 @@ void cache_unregister(struct cache_detail *cd)
|
|||||||
out:
|
out:
|
||||||
printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name);
|
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
|
/* clean cache tries to find something to clean
|
||||||
* and cleans it.
|
* and cleans it.
|
||||||
@@ -687,18 +626,18 @@ struct cache_reader {
|
|||||||
int offset; /* if non-0, we have a refcnt on next request */
|
int offset; /* if non-0, we have a refcnt on next request */
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t cache_read(struct file *filp, char __user *buf, size_t count,
|
||||||
cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
|
loff_t *ppos, struct cache_detail *cd)
|
||||||
{
|
{
|
||||||
struct cache_reader *rp = filp->private_data;
|
struct cache_reader *rp = filp->private_data;
|
||||||
struct cache_request *rq;
|
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;
|
int err;
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return 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 */
|
* readers on this file */
|
||||||
again:
|
again:
|
||||||
spin_lock(&queue_lock);
|
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) {
|
if (rp->q.list.next == &cd->queue) {
|
||||||
spin_unlock(&queue_lock);
|
spin_unlock(&queue_lock);
|
||||||
mutex_unlock(&queue_io_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
BUG_ON(rp->offset);
|
BUG_ON(rp->offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -758,49 +697,90 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
|
|||||||
}
|
}
|
||||||
if (err == -EAGAIN)
|
if (err == -EAGAIN)
|
||||||
goto again;
|
goto again;
|
||||||
mutex_unlock(&queue_io_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
return err ? err : count;
|
return err ? err : count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char write_buf[8192]; /* protected by queue_io_mutex */
|
static ssize_t cache_do_downcall(char *kaddr, const char __user *buf,
|
||||||
|
size_t count, struct cache_detail *cd)
|
||||||
static ssize_t
|
|
||||||
cache_write(struct file *filp, const char __user *buf, size_t count,
|
|
||||||
loff_t *ppos)
|
|
||||||
{
|
{
|
||||||
int err;
|
ssize_t ret;
|
||||||
struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
|
|
||||||
|
|
||||||
if (count == 0)
|
if (copy_from_user(kaddr, buf, count))
|
||||||
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);
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
kaddr[count] = '\0';
|
||||||
write_buf[count] = '\0';
|
ret = cd->cache_parse(cd, kaddr, count);
|
||||||
if (cd->cache_parse)
|
if (!ret)
|
||||||
err = cd->cache_parse(cd, write_buf, count);
|
ret = count;
|
||||||
else
|
return ret;
|
||||||
err = -EINVAL;
|
}
|
||||||
|
|
||||||
|
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);
|
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 DECLARE_WAIT_QUEUE_HEAD(queue_wait);
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int cache_poll(struct file *filp, poll_table *wait,
|
||||||
cache_poll(struct file *filp, poll_table *wait)
|
struct cache_detail *cd)
|
||||||
{
|
{
|
||||||
unsigned int mask;
|
unsigned int mask;
|
||||||
struct cache_reader *rp = filp->private_data;
|
struct cache_reader *rp = filp->private_data;
|
||||||
struct cache_queue *cq;
|
struct cache_queue *cq;
|
||||||
struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
|
|
||||||
|
|
||||||
poll_wait(filp, &queue_wait, wait);
|
poll_wait(filp, &queue_wait, wait);
|
||||||
|
|
||||||
@@ -822,14 +802,13 @@ cache_poll(struct file *filp, poll_table *wait)
|
|||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int cache_ioctl(struct inode *ino, struct file *filp,
|
||||||
cache_ioctl(struct inode *ino, struct file *filp,
|
unsigned int cmd, unsigned long arg,
|
||||||
unsigned int cmd, unsigned long arg)
|
struct cache_detail *cd)
|
||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
struct cache_reader *rp = filp->private_data;
|
struct cache_reader *rp = filp->private_data;
|
||||||
struct cache_queue *cq;
|
struct cache_queue *cq;
|
||||||
struct cache_detail *cd = PDE(ino)->data;
|
|
||||||
|
|
||||||
if (cmd != FIONREAD || !rp)
|
if (cmd != FIONREAD || !rp)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -852,15 +831,13 @@ cache_ioctl(struct inode *ino, struct file *filp,
|
|||||||
return put_user(len, (int __user *)arg);
|
return put_user(len, (int __user *)arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int cache_open(struct inode *inode, struct file *filp,
|
||||||
cache_open(struct inode *inode, struct file *filp)
|
struct cache_detail *cd)
|
||||||
{
|
{
|
||||||
struct cache_reader *rp = NULL;
|
struct cache_reader *rp = NULL;
|
||||||
|
|
||||||
nonseekable_open(inode, filp);
|
nonseekable_open(inode, filp);
|
||||||
if (filp->f_mode & FMODE_READ) {
|
if (filp->f_mode & FMODE_READ) {
|
||||||
struct cache_detail *cd = PDE(inode)->data;
|
|
||||||
|
|
||||||
rp = kmalloc(sizeof(*rp), GFP_KERNEL);
|
rp = kmalloc(sizeof(*rp), GFP_KERNEL);
|
||||||
if (!rp)
|
if (!rp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -875,11 +852,10 @@ cache_open(struct inode *inode, struct file *filp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int cache_release(struct inode *inode, struct file *filp,
|
||||||
cache_release(struct inode *inode, struct file *filp)
|
struct cache_detail *cd)
|
||||||
{
|
{
|
||||||
struct cache_reader *rp = filp->private_data;
|
struct cache_reader *rp = filp->private_data;
|
||||||
struct cache_detail *cd = PDE(inode)->data;
|
|
||||||
|
|
||||||
if (rp) {
|
if (rp) {
|
||||||
spin_lock(&queue_lock);
|
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)
|
static void queue_loose(struct cache_detail *detail, struct cache_head *ch)
|
||||||
{
|
{
|
||||||
struct cache_queue *cq;
|
struct cache_queue *cq;
|
||||||
@@ -1020,15 +984,21 @@ static void warn_no_listener(struct cache_detail *detail)
|
|||||||
if (detail->last_warn != detail->last_close) {
|
if (detail->last_warn != detail->last_close) {
|
||||||
detail->last_warn = detail->last_close;
|
detail->last_warn = detail->last_close;
|
||||||
if (detail->warn_no_listener)
|
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.
|
* 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;
|
char *buf;
|
||||||
@@ -1036,9 +1006,6 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h)
|
|||||||
char *bp;
|
char *bp;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (detail->cache_request == NULL)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (atomic_read(&detail->readers) == 0 &&
|
if (atomic_read(&detail->readers) == 0 &&
|
||||||
detail->last_close < get_seconds() - 30) {
|
detail->last_close < get_seconds() - 30) {
|
||||||
warn_no_listener(detail);
|
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;
|
bp = buf; len = PAGE_SIZE;
|
||||||
|
|
||||||
detail->cache_request(detail, h, &bp, &len);
|
cache_request(detail, h, &bp, &len);
|
||||||
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
@@ -1075,6 +1042,7 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h)
|
|||||||
wake_up(&queue_wait);
|
wake_up(&queue_wait);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parse a message from user-space and pass it
|
* parse a message from user-space and pass it
|
||||||
@@ -1242,10 +1210,10 @@ static const struct seq_operations cache_content_op = {
|
|||||||
.show = c_show,
|
.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 handle *han;
|
||||||
struct cache_detail *cd = PDE(inode)->data;
|
|
||||||
|
|
||||||
han = __seq_open_private(file, &cache_content_op, sizeof(*han));
|
han = __seq_open_private(file, &cache_content_op, sizeof(*han));
|
||||||
if (han == NULL)
|
if (han == NULL)
|
||||||
@@ -1255,17 +1223,10 @@ static int content_open(struct inode *inode, struct file *file)
|
|||||||
return 0;
|
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,
|
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];
|
char tbuf[20];
|
||||||
unsigned long p = *ppos;
|
unsigned long p = *ppos;
|
||||||
size_t len;
|
size_t len;
|
||||||
@@ -1283,10 +1244,10 @@ static ssize_t read_flush(struct file *file, char __user *buf,
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t write_flush(struct file * file, const char __user * buf,
|
static ssize_t write_flush(struct file *file, const 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];
|
char tbuf[20];
|
||||||
char *ep;
|
char *ep;
|
||||||
long flushtime;
|
long flushtime;
|
||||||
@@ -1307,8 +1268,299 @@ static ssize_t write_flush(struct file * file, const char __user * buf,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations cache_flush_operations = {
|
static ssize_t cache_read_procfs(struct file *filp, char __user *buf,
|
||||||
.open = nonseekable_open,
|
size_t count, loff_t *ppos)
|
||||||
.read = read_flush,
|
{
|
||||||
.write = write_flush,
|
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/types.h>
|
||||||
#include <linux/kallsyms.h>
|
#include <linux/kallsyms.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
#include <linux/namei.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
@@ -97,33 +99,49 @@ static int
|
|||||||
rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
|
rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
|
||||||
{
|
{
|
||||||
static uint32_t clntid;
|
static uint32_t clntid;
|
||||||
|
struct nameidata nd;
|
||||||
|
struct path path;
|
||||||
|
char name[15];
|
||||||
|
struct qstr q = {
|
||||||
|
.name = name,
|
||||||
|
};
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
clnt->cl_vfsmnt = ERR_PTR(-ENOENT);
|
clnt->cl_path.mnt = ERR_PTR(-ENOENT);
|
||||||
clnt->cl_dentry = ERR_PTR(-ENOENT);
|
clnt->cl_path.dentry = ERR_PTR(-ENOENT);
|
||||||
if (dir_name == NULL)
|
if (dir_name == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
clnt->cl_vfsmnt = rpc_get_mount();
|
path.mnt = rpc_get_mount();
|
||||||
if (IS_ERR(clnt->cl_vfsmnt))
|
if (IS_ERR(path.mnt))
|
||||||
return PTR_ERR(clnt->cl_vfsmnt);
|
return PTR_ERR(path.mnt);
|
||||||
|
error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &nd);
|
||||||
|
if (error)
|
||||||
|
goto err;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname),
|
q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
|
||||||
"%s/clnt%x", dir_name,
|
name[sizeof(name) - 1] = '\0';
|
||||||
(unsigned int)clntid++);
|
q.hash = full_name_hash(q.name, q.len);
|
||||||
clnt->cl_pathname[sizeof(clnt->cl_pathname) - 1] = '\0';
|
path.dentry = rpc_create_client_dir(nd.path.dentry, &q, clnt);
|
||||||
clnt->cl_dentry = rpc_mkdir(clnt->cl_pathname, clnt);
|
if (!IS_ERR(path.dentry))
|
||||||
if (!IS_ERR(clnt->cl_dentry))
|
break;
|
||||||
return 0;
|
error = PTR_ERR(path.dentry);
|
||||||
error = PTR_ERR(clnt->cl_dentry);
|
|
||||||
if (error != -EEXIST) {
|
if (error != -EEXIST) {
|
||||||
printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n",
|
printk(KERN_INFO "RPC: Couldn't create pipefs entry"
|
||||||
clnt->cl_pathname, error);
|
" %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();
|
rpc_put_mount();
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
|
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;
|
return clnt;
|
||||||
|
|
||||||
out_no_auth:
|
out_no_auth:
|
||||||
if (!IS_ERR(clnt->cl_dentry)) {
|
if (!IS_ERR(clnt->cl_path.dentry)) {
|
||||||
rpc_rmdir(clnt->cl_dentry);
|
rpc_remove_client_dir(clnt->cl_path.dentry);
|
||||||
rpc_put_mount();
|
rpc_put_mount();
|
||||||
}
|
}
|
||||||
out_no_path:
|
out_no_path:
|
||||||
@@ -423,8 +441,8 @@ rpc_free_client(struct kref *kref)
|
|||||||
|
|
||||||
dprintk("RPC: destroying %s client for %s\n",
|
dprintk("RPC: destroying %s client for %s\n",
|
||||||
clnt->cl_protname, clnt->cl_server);
|
clnt->cl_protname, clnt->cl_server);
|
||||||
if (!IS_ERR(clnt->cl_dentry)) {
|
if (!IS_ERR(clnt->cl_path.dentry)) {
|
||||||
rpc_rmdir(clnt->cl_dentry);
|
rpc_remove_client_dir(clnt->cl_path.dentry);
|
||||||
rpc_put_mount();
|
rpc_put_mount();
|
||||||
}
|
}
|
||||||
if (clnt->cl_parent != clnt) {
|
if (clnt->cl_parent != clnt) {
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/sunrpc/rpc_pipe_fs.h>
|
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||||
|
#include <linux/sunrpc/cache.h>
|
||||||
|
|
||||||
static struct vfsmount *rpc_mount __read_mostly;
|
static struct vfsmount *rpc_mount __read_mostly;
|
||||||
static int rpc_mount_count;
|
static int rpc_mount_count;
|
||||||
@@ -125,7 +126,7 @@ static void
|
|||||||
rpc_close_pipes(struct inode *inode)
|
rpc_close_pipes(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct rpc_inode *rpci = RPC_I(inode);
|
struct rpc_inode *rpci = RPC_I(inode);
|
||||||
struct rpc_pipe_ops *ops;
|
const struct rpc_pipe_ops *ops;
|
||||||
int need_release;
|
int need_release;
|
||||||
|
|
||||||
mutex_lock(&inode->i_mutex);
|
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.
|
* Description of fs contents.
|
||||||
*/
|
*/
|
||||||
struct rpc_filelist {
|
struct rpc_filelist {
|
||||||
char *name;
|
const char *name;
|
||||||
const struct file_operations *i_fop;
|
const struct file_operations *i_fop;
|
||||||
int mode;
|
umode_t 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,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vfsmount *rpc_get_mount(void)
|
struct vfsmount *rpc_get_mount(void)
|
||||||
@@ -484,39 +431,8 @@ static const struct dentry_operations rpc_dentry_operations = {
|
|||||||
.d_delete = rpc_delete_dentry,
|
.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 *
|
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);
|
struct inode *inode = new_inode(sb);
|
||||||
if (!inode)
|
if (!inode)
|
||||||
@@ -534,212 +450,274 @@ rpc_get_inode(struct super_block *sb, int mode)
|
|||||||
return inode;
|
return inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int __rpc_create_common(struct inode *dir, struct dentry *dentry,
|
||||||
* FIXME: This probably has races.
|
umode_t mode,
|
||||||
*/
|
const struct file_operations *i_fop,
|
||||||
static void rpc_depopulate(struct dentry *parent,
|
void *private)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
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)
|
if (!inode)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
inode->i_ino = iunique(dir->i_sb, 100);
|
inode->i_ino = iunique(dir->i_sb, 100);
|
||||||
d_instantiate(dentry, inode);
|
if (i_fop)
|
||||||
inc_nlink(dir);
|
inode->i_fop = i_fop;
|
||||||
fsnotify_mkdir(dir, dentry);
|
if (private)
|
||||||
|
rpc_inode_setowner(inode, private);
|
||||||
|
d_add(dentry, inode);
|
||||||
return 0;
|
return 0;
|
||||||
out_err:
|
out_err:
|
||||||
printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
|
printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
|
||||||
__FILE__, __func__, dentry->d_name.name);
|
__FILE__, __func__, dentry->d_name.name);
|
||||||
|
dput(dentry);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int __rpc_create(struct inode *dir, struct dentry *dentry,
|
||||||
__rpc_rmdir(struct inode *dir, struct dentry *dentry)
|
umode_t mode,
|
||||||
|
const struct file_operations *i_fop,
|
||||||
|
void *private)
|
||||||
{
|
{
|
||||||
int error;
|
int err;
|
||||||
error = simple_rmdir(dir, dentry);
|
|
||||||
if (!error)
|
err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private);
|
||||||
d_delete(dentry);
|
if (err)
|
||||||
return error;
|
return err;
|
||||||
|
fsnotify_create(dir, dentry);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dentry *
|
static int __rpc_mkdir(struct inode *dir, struct dentry *dentry,
|
||||||
rpc_lookup_create(struct dentry *parent, const char *name, int len, int exclusive)
|
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 inode *dir = parent->d_inode;
|
||||||
struct dentry *dentry;
|
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);
|
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))
|
if (IS_ERR(dentry))
|
||||||
|
goto out;
|
||||||
|
error = __rpc_mkdir(dir, dentry, mode, NULL, private);
|
||||||
|
if (error != 0)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
if (!dentry->d_inode)
|
if (populate != NULL) {
|
||||||
dentry->d_op = &rpc_dentry_operations;
|
error = populate(dentry, args_populate);
|
||||||
else if (exclusive) {
|
|
||||||
dput(dentry);
|
|
||||||
dentry = ERR_PTR(-EEXIST);
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
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)
|
if (error)
|
||||||
goto err_depopulate;
|
goto err_rmdir;
|
||||||
dget(dentry);
|
}
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&dir->i_mutex);
|
mutex_unlock(&dir->i_mutex);
|
||||||
rpc_release_path(&nd);
|
|
||||||
return dentry;
|
return dentry;
|
||||||
err_depopulate:
|
err_rmdir:
|
||||||
rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF);
|
|
||||||
__rpc_rmdir(dir, dentry);
|
__rpc_rmdir(dir, dentry);
|
||||||
err_dput:
|
out_err:
|
||||||
dput(dentry);
|
|
||||||
printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n",
|
|
||||||
__FILE__, __func__, path, error);
|
|
||||||
dentry = ERR_PTR(error);
|
dentry = ERR_PTR(error);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static int rpc_rmdir_depopulate(struct dentry *dentry,
|
||||||
* rpc_rmdir - Remove a directory created with rpc_mkdir()
|
void (*depopulate)(struct dentry *))
|
||||||
* @dentry: directory to remove
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
rpc_rmdir(struct dentry *dentry)
|
|
||||||
{
|
{
|
||||||
struct dentry *parent;
|
struct dentry *parent;
|
||||||
struct inode *dir;
|
struct inode *dir;
|
||||||
@@ -748,9 +726,9 @@ rpc_rmdir(struct dentry *dentry)
|
|||||||
parent = dget_parent(dentry);
|
parent = dget_parent(dentry);
|
||||||
dir = parent->d_inode;
|
dir = parent->d_inode;
|
||||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
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);
|
error = __rpc_rmdir(dir, dentry);
|
||||||
dput(dentry);
|
|
||||||
mutex_unlock(&dir->i_mutex);
|
mutex_unlock(&dir->i_mutex);
|
||||||
dput(parent);
|
dput(parent);
|
||||||
return error;
|
return error;
|
||||||
@@ -776,50 +754,54 @@ rpc_rmdir(struct dentry *dentry)
|
|||||||
* The @private argument passed here will be available to all these methods
|
* 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.
|
* from the file pointer, via RPC_I(file->f_dentry->d_inode)->private.
|
||||||
*/
|
*/
|
||||||
struct dentry *
|
struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,
|
||||||
rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags)
|
void *private, const struct rpc_pipe_ops *ops,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct inode *dir, *inode;
|
struct inode *dir = parent->d_inode;
|
||||||
struct rpc_inode *rpci;
|
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))
|
if (IS_ERR(dentry))
|
||||||
return dentry;
|
goto out;
|
||||||
dir = parent->d_inode;
|
|
||||||
if (dentry->d_inode) {
|
if (dentry->d_inode) {
|
||||||
rpci = RPC_I(dentry->d_inode);
|
struct rpc_inode *rpci = RPC_I(dentry->d_inode);
|
||||||
if (rpci->private != private ||
|
if (rpci->private != private ||
|
||||||
rpci->ops != ops ||
|
rpci->ops != ops ||
|
||||||
rpci->flags != flags) {
|
rpci->flags != flags) {
|
||||||
dput (dentry);
|
dput (dentry);
|
||||||
dentry = ERR_PTR(-EBUSY);
|
err = -EBUSY;
|
||||||
|
goto out_err;
|
||||||
}
|
}
|
||||||
rpci->nkern_readwriters++;
|
rpci->nkern_readwriters++;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR);
|
|
||||||
if (!inode)
|
err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops,
|
||||||
goto err_dput;
|
private, ops, flags);
|
||||||
inode->i_ino = iunique(dir->i_sb, 100);
|
if (err)
|
||||||
inode->i_fop = &rpc_pipe_fops;
|
goto out_err;
|
||||||
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);
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&dir->i_mutex);
|
mutex_unlock(&dir->i_mutex);
|
||||||
return dentry;
|
return dentry;
|
||||||
err_dput:
|
out_err:
|
||||||
dput(dentry);
|
dentry = ERR_PTR(err);
|
||||||
dentry = ERR_PTR(-ENOMEM);
|
|
||||||
printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n",
|
printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n",
|
||||||
__FILE__, __func__, parent->d_name.name, name,
|
__FILE__, __func__, parent->d_name.name, name,
|
||||||
-ENOMEM);
|
err);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rpc_mkpipe);
|
EXPORT_SYMBOL_GPL(rpc_mkpipe);
|
||||||
@@ -842,19 +824,107 @@ rpc_unlink(struct dentry *dentry)
|
|||||||
parent = dget_parent(dentry);
|
parent = dget_parent(dentry);
|
||||||
dir = parent->d_inode;
|
dir = parent->d_inode;
|
||||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||||
if (--RPC_I(dentry->d_inode)->nkern_readwriters == 0) {
|
error = __rpc_rmpipe(dir, dentry);
|
||||||
rpc_close_pipes(dentry->d_inode);
|
|
||||||
error = simple_unlink(dir, dentry);
|
|
||||||
if (!error)
|
|
||||||
d_delete(dentry);
|
|
||||||
}
|
|
||||||
dput(dentry);
|
|
||||||
mutex_unlock(&dir->i_mutex);
|
mutex_unlock(&dir->i_mutex);
|
||||||
dput(parent);
|
dput(parent);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rpc_unlink);
|
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
|
* populate the filesystem
|
||||||
*/
|
*/
|
||||||
@@ -866,6 +936,46 @@ static struct super_operations s_ops = {
|
|||||||
|
|
||||||
#define RPCAUTH_GSSMAGIC 0x67596969
|
#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
|
static int
|
||||||
rpc_fill_super(struct super_block *sb, void *data, int silent)
|
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);
|
iput(inode);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
if (rpc_populate(root, files, RPCAUTH_Root + 1, RPCAUTH_RootEOF))
|
if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
|
||||||
goto out;
|
goto out;
|
||||||
sb->s_root = root;
|
sb->s_root = root;
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -171,6 +171,11 @@ static void ip_map_request(struct cache_detail *cd,
|
|||||||
(*bpp)[-1] = '\n';
|
(*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 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);
|
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,
|
.hash_table = ip_table,
|
||||||
.name = "auth.unix.ip",
|
.name = "auth.unix.ip",
|
||||||
.cache_put = ip_map_put,
|
.cache_put = ip_map_put,
|
||||||
.cache_request = ip_map_request,
|
.cache_upcall = ip_map_upcall,
|
||||||
.cache_parse = ip_map_parse,
|
.cache_parse = ip_map_parse,
|
||||||
.cache_show = ip_map_show,
|
.cache_show = ip_map_show,
|
||||||
.match = ip_map_match,
|
.match = ip_map_match,
|
||||||
@@ -523,6 +528,11 @@ static void unix_gid_request(struct cache_detail *cd,
|
|||||||
(*bpp)[-1] = '\n';
|
(*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);
|
static struct unix_gid *unix_gid_lookup(uid_t uid);
|
||||||
extern struct cache_detail unix_gid_cache;
|
extern struct cache_detail unix_gid_cache;
|
||||||
|
|
||||||
@@ -622,7 +632,7 @@ struct cache_detail unix_gid_cache = {
|
|||||||
.hash_table = gid_table,
|
.hash_table = gid_table,
|
||||||
.name = "auth.unix.gid",
|
.name = "auth.unix.gid",
|
||||||
.cache_put = unix_gid_put,
|
.cache_put = unix_gid_put,
|
||||||
.cache_request = unix_gid_request,
|
.cache_upcall = unix_gid_upcall,
|
||||||
.cache_parse = unix_gid_parse,
|
.cache_parse = unix_gid_parse,
|
||||||
.cache_show = unix_gid_show,
|
.cache_show = unix_gid_show,
|
||||||
.match = unix_gid_match,
|
.match = unix_gid_match,
|
||||||
|
Reference in New Issue
Block a user