Merge branch 'nfs-for-2.6.32' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6 into for-2.6.32-incoming

Conflicts:
	net/sunrpc/cache.c
This commit is contained in:
J. Bruce Fields
2009-08-21 11:27:29 -04:00
2349 changed files with 64255 additions and 34601 deletions

View File

@@ -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,12 @@ 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);
}
static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h)
{
@@ -192,6 +199,7 @@ static inline int cache_is_valid(struct cache_detail *detail, struct cache_head
return 0;
}
}
/*
* This is the generic cache management routine for all
* the authentication caches.
@@ -297,76 +305,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);
@@ -380,11 +323,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);
@@ -399,7 +340,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);
@@ -408,7 +348,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.
@@ -703,18 +642,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);
@@ -727,7 +666,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;
}
@@ -774,49 +713,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);
@@ -838,14 +818,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;
@@ -868,15 +847,15 @@ 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;
if (!cd || !try_module_get(cd->owner))
return -EACCES;
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;
@@ -891,11 +870,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);
@@ -919,23 +897,12 @@ cache_release(struct inode *inode, struct file *filp)
cd->last_close = get_seconds();
atomic_dec(&cd->readers);
}
module_put(cd->owner);
return 0;
}
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 cache_dequeue(struct cache_detail *detail, struct cache_head *ch)
{
struct cache_queue *cq;
@@ -1036,15 +1003,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;
@@ -1052,9 +1025,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);
@@ -1073,7 +1043,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);
@@ -1091,6 +1061,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
@@ -1258,11 +1229,13 @@ 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;
if (!cd || !try_module_get(cd->owner))
return -EACCES;
han = __seq_open_private(file, &cache_content_op, sizeof(*han));
if (han == NULL)
return -ENOMEM;
@@ -1271,17 +1244,33 @@ 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 int content_release(struct inode *inode, struct file *file,
struct cache_detail *cd)
{
int ret = seq_release_private(inode, file);
module_put(cd->owner);
return ret;
}
static int open_flush(struct inode *inode, struct file *file,
struct cache_detail *cd)
{
if (!cd || !try_module_get(cd->owner))
return -EACCES;
return nonseekable_open(inode, file);
}
static int release_flush(struct inode *inode, struct file *file,
struct cache_detail *cd)
{
module_put(cd->owner);
return 0;
}
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;
@@ -1299,10 +1288,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;
@@ -1323,8 +1312,343 @@ 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 int content_release_procfs(struct inode *inode, struct file *filp)
{
struct cache_detail *cd = PDE(inode)->data;
return content_release(inode, filp, cd);
}
static const struct file_operations content_file_operations_procfs = {
.open = content_open_procfs,
.read = seq_read,
.llseek = seq_lseek,
.release = content_release_procfs,
};
static int open_flush_procfs(struct inode *inode, struct file *filp)
{
struct cache_detail *cd = PDE(inode)->data;
return open_flush(inode, filp, cd);
}
static int release_flush_procfs(struct inode *inode, struct file *filp)
{
struct cache_detail *cd = PDE(inode)->data;
return release_flush(inode, filp, cd);
}
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 = open_flush_procfs,
.read = read_flush_procfs,
.write = write_flush_procfs,
.release = release_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);
}
static int content_release_pipefs(struct inode *inode, struct file *filp)
{
struct cache_detail *cd = RPC_I(inode)->private;
return content_release(inode, filp, cd);
}
const struct file_operations content_file_operations_pipefs = {
.open = content_open_pipefs,
.read = seq_read,
.llseek = seq_lseek,
.release = content_release_pipefs,
};
static int open_flush_pipefs(struct inode *inode, struct file *filp)
{
struct cache_detail *cd = RPC_I(inode)->private;
return open_flush(inode, filp, cd);
}
static int release_flush_pipefs(struct inode *inode, struct file *filp)
{
struct cache_detail *cd = RPC_I(inode)->private;
return release_flush(inode, filp, cd);
}
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 = open_flush_pipefs,
.read = read_flush_pipefs,
.write = write_flush_pipefs,
.release = release_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);