Commit c4bc705e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi:
 "The biggest part of this pull request is a patch series from Maxim
  Patlasov to optimize scatter-gather direct IO.  There's also the
  addition of a "readdirplus" API, poll events and various fixes and
  cleanups.

  There's a one line change outside of fuse to mm/filemap.c which makes
  the argument of iov_iter_single_seg_count() const, required by Maxim's
  patches."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (22 commits)
  fuse: allow control of adaptive readdirplus use
  Synchronize fuse header with one used in library
  fuse: send poll events
  fuse: don't WARN when nlink is zero
  fuse: avoid out-of-scope stack access
  fuse: bump version for READDIRPLUS
  FUSE: Adapt readdirplus to application usage patterns
  Do not use RCU for current process credentials
  fuse: cleanup fuse_direct_io()
  fuse: optimize __fuse_direct_io()
  fuse: optimize fuse_get_user_pages()
  fuse: pass iov[] to fuse_get_user_pages()
  mm: minor cleanup of iov_iter_single_seg_count()
  fuse: use req->page_descs[] for argpages cases
  fuse: add per-page descriptor <offset, length> to fuse_req
  fuse: rework fuse_do_ioctl()
  fuse: rework fuse_perform_write()
  fuse: rework fuse_readpages()
  fuse: rework fuse_retrieve()
  fuse: categorize fuse_get_req()
  ...
parents 2608e3d0 634734b6
...@@ -91,19 +91,22 @@ static ssize_t cuse_read(struct file *file, char __user *buf, size_t count, ...@@ -91,19 +91,22 @@ static ssize_t cuse_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos) loff_t *ppos)
{ {
loff_t pos = 0; loff_t pos = 0;
struct iovec iov = { .iov_base = buf, .iov_len = count };
return fuse_direct_io(file, buf, count, &pos, 0); return fuse_direct_io(file, &iov, 1, count, &pos, 0);
} }
static ssize_t cuse_write(struct file *file, const char __user *buf, static ssize_t cuse_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
loff_t pos = 0; loff_t pos = 0;
struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count };
/* /*
* No locking or generic_write_checks(), the server is * No locking or generic_write_checks(), the server is
* responsible for locking and sanity checks. * responsible for locking and sanity checks.
*/ */
return fuse_direct_io(file, buf, count, &pos, 1); return fuse_direct_io(file, &iov, 1, count, &pos, 1);
} }
static int cuse_open(struct inode *inode, struct file *file) static int cuse_open(struct inode *inode, struct file *file)
...@@ -419,7 +422,7 @@ static int cuse_send_init(struct cuse_conn *cc) ...@@ -419,7 +422,7 @@ static int cuse_send_init(struct cuse_conn *cc)
BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE); BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE);
req = fuse_get_req(fc); req = fuse_get_req(fc, 1);
if (IS_ERR(req)) { if (IS_ERR(req)) {
rc = PTR_ERR(req); rc = PTR_ERR(req);
goto err; goto err;
...@@ -449,6 +452,7 @@ static int cuse_send_init(struct cuse_conn *cc) ...@@ -449,6 +452,7 @@ static int cuse_send_init(struct cuse_conn *cc)
req->out.argvar = 1; req->out.argvar = 1;
req->out.argpages = 1; req->out.argpages = 1;
req->pages[0] = page; req->pages[0] = page;
req->page_descs[0].length = req->out.args[1].size;
req->num_pages = 1; req->num_pages = 1;
req->end = cuse_process_init_reply; req->end = cuse_process_init_reply;
fuse_request_send_background(fc, req); fuse_request_send_background(fc, req);
......
...@@ -34,34 +34,67 @@ static struct fuse_conn *fuse_get_conn(struct file *file) ...@@ -34,34 +34,67 @@ static struct fuse_conn *fuse_get_conn(struct file *file)
return file->private_data; return file->private_data;
} }
static void fuse_request_init(struct fuse_req *req) static void fuse_request_init(struct fuse_req *req, struct page **pages,
struct fuse_page_desc *page_descs,
unsigned npages)
{ {
memset(req, 0, sizeof(*req)); memset(req, 0, sizeof(*req));
memset(pages, 0, sizeof(*pages) * npages);
memset(page_descs, 0, sizeof(*page_descs) * npages);
INIT_LIST_HEAD(&req->list); INIT_LIST_HEAD(&req->list);
INIT_LIST_HEAD(&req->intr_entry); INIT_LIST_HEAD(&req->intr_entry);
init_waitqueue_head(&req->waitq); init_waitqueue_head(&req->waitq);
atomic_set(&req->count, 1); atomic_set(&req->count, 1);
req->pages = pages;
req->page_descs = page_descs;
req->max_pages = npages;
} }
struct fuse_req *fuse_request_alloc(void) static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags)
{ {
struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_KERNEL); struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, flags);
if (req) if (req) {
fuse_request_init(req); struct page **pages;
struct fuse_page_desc *page_descs;
if (npages <= FUSE_REQ_INLINE_PAGES) {
pages = req->inline_pages;
page_descs = req->inline_page_descs;
} else {
pages = kmalloc(sizeof(struct page *) * npages, flags);
page_descs = kmalloc(sizeof(struct fuse_page_desc) *
npages, flags);
}
if (!pages || !page_descs) {
kfree(pages);
kfree(page_descs);
kmem_cache_free(fuse_req_cachep, req);
return NULL;
}
fuse_request_init(req, pages, page_descs, npages);
}
return req; return req;
} }
struct fuse_req *fuse_request_alloc(unsigned npages)
{
return __fuse_request_alloc(npages, GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(fuse_request_alloc); EXPORT_SYMBOL_GPL(fuse_request_alloc);
struct fuse_req *fuse_request_alloc_nofs(void) struct fuse_req *fuse_request_alloc_nofs(unsigned npages)
{ {
struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_NOFS); return __fuse_request_alloc(npages, GFP_NOFS);
if (req)
fuse_request_init(req);
return req;
} }
void fuse_request_free(struct fuse_req *req) void fuse_request_free(struct fuse_req *req)
{ {
if (req->pages != req->inline_pages) {
kfree(req->pages);
kfree(req->page_descs);
}
kmem_cache_free(fuse_req_cachep, req); kmem_cache_free(fuse_req_cachep, req);
} }
...@@ -97,7 +130,7 @@ static void fuse_req_init_context(struct fuse_req *req) ...@@ -97,7 +130,7 @@ static void fuse_req_init_context(struct fuse_req *req)
req->in.h.pid = current->pid; req->in.h.pid = current->pid;
} }
struct fuse_req *fuse_get_req(struct fuse_conn *fc) struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages)
{ {
struct fuse_req *req; struct fuse_req *req;
sigset_t oldset; sigset_t oldset;
...@@ -116,7 +149,7 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc) ...@@ -116,7 +149,7 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
if (!fc->connected) if (!fc->connected)
goto out; goto out;
req = fuse_request_alloc(); req = fuse_request_alloc(npages);
err = -ENOMEM; err = -ENOMEM;
if (!req) if (!req)
goto out; goto out;
...@@ -165,7 +198,7 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) ...@@ -165,7 +198,7 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req)
struct fuse_file *ff = file->private_data; struct fuse_file *ff = file->private_data;
spin_lock(&fc->lock); spin_lock(&fc->lock);
fuse_request_init(req); fuse_request_init(req, req->pages, req->page_descs, req->max_pages);
BUG_ON(ff->reserved_req); BUG_ON(ff->reserved_req);
ff->reserved_req = req; ff->reserved_req = req;
wake_up_all(&fc->reserved_req_waitq); wake_up_all(&fc->reserved_req_waitq);
...@@ -186,13 +219,14 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) ...@@ -186,13 +219,14 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req)
* filesystem should not have it's own file open. If deadlock is * filesystem should not have it's own file open. If deadlock is
* intentional, it can still be broken by "aborting" the filesystem. * intentional, it can still be broken by "aborting" the filesystem.
*/ */
struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file) struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc,
struct file *file)
{ {
struct fuse_req *req; struct fuse_req *req;
atomic_inc(&fc->num_waiting); atomic_inc(&fc->num_waiting);
wait_event(fc->blocked_waitq, !fc->blocked); wait_event(fc->blocked_waitq, !fc->blocked);
req = fuse_request_alloc(); req = fuse_request_alloc(0);
if (!req) if (!req)
req = get_reserved_req(fc, file); req = get_reserved_req(fc, file);
...@@ -406,9 +440,8 @@ __acquires(fc->lock) ...@@ -406,9 +440,8 @@ __acquires(fc->lock)
} }
} }
void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{ {
req->isreply = 1;
spin_lock(&fc->lock); spin_lock(&fc->lock);
if (!fc->connected) if (!fc->connected)
req->out.h.error = -ENOTCONN; req->out.h.error = -ENOTCONN;
...@@ -425,6 +458,12 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) ...@@ -425,6 +458,12 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
} }
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
} }
void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{
req->isreply = 1;
__fuse_request_send(fc, req);
}
EXPORT_SYMBOL_GPL(fuse_request_send); EXPORT_SYMBOL_GPL(fuse_request_send);
static void fuse_request_send_nowait_locked(struct fuse_conn *fc, static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
...@@ -491,6 +530,27 @@ void fuse_request_send_background_locked(struct fuse_conn *fc, ...@@ -491,6 +530,27 @@ void fuse_request_send_background_locked(struct fuse_conn *fc,
fuse_request_send_nowait_locked(fc, req); fuse_request_send_nowait_locked(fc, req);
} }
void fuse_force_forget(struct file *file, u64 nodeid)
{
struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_forget_in inarg;
memset(&inarg, 0, sizeof(inarg));
inarg.nlookup = 1;
req = fuse_get_req_nofail_nopages(fc, file);
req->in.h.opcode = FUSE_FORGET;
req->in.h.nodeid = nodeid;
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
req->isreply = 0;
__fuse_request_send(fc, req);
/* ignore errors */
fuse_put_request(fc, req);
}
/* /*
* Lock the request. Up to the next unlock_request() there mustn't be * Lock the request. Up to the next unlock_request() there mustn't be
* anything that could cause a page-fault. If the request was already * anything that could cause a page-fault. If the request was already
...@@ -850,11 +910,11 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes, ...@@ -850,11 +910,11 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
{ {
unsigned i; unsigned i;
struct fuse_req *req = cs->req; struct fuse_req *req = cs->req;
unsigned offset = req->page_offset;
unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset);
for (i = 0; i < req->num_pages && (nbytes || zeroing); i++) { for (i = 0; i < req->num_pages && (nbytes || zeroing); i++) {
int err; int err;
unsigned offset = req->page_descs[i].offset;
unsigned count = min(nbytes, req->page_descs[i].length);
err = fuse_copy_page(cs, &req->pages[i], offset, count, err = fuse_copy_page(cs, &req->pages[i], offset, count,
zeroing); zeroing);
...@@ -862,8 +922,6 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes, ...@@ -862,8 +922,6 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
return err; return err;
nbytes -= count; nbytes -= count;
count = min(nbytes, (unsigned) PAGE_SIZE);
offset = 0;
} }
return 0; return 0;
} }
...@@ -1536,29 +1594,34 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, ...@@ -1536,29 +1594,34 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
unsigned int num; unsigned int num;
unsigned int offset; unsigned int offset;
size_t total_len = 0; size_t total_len = 0;
int num_pages;
offset = outarg->offset & ~PAGE_CACHE_MASK;
file_size = i_size_read(inode);
num = outarg->size;
if (outarg->offset > file_size)
num = 0;
else if (outarg->offset + num > file_size)
num = file_size - outarg->offset;
req = fuse_get_req(fc); num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
num_pages = min(num_pages, FUSE_MAX_PAGES_PER_REQ);
req = fuse_get_req(fc, num_pages);
if (IS_ERR(req)) if (IS_ERR(req))
return PTR_ERR(req); return PTR_ERR(req);
offset = outarg->offset & ~PAGE_CACHE_MASK;
req->in.h.opcode = FUSE_NOTIFY_REPLY; req->in.h.opcode = FUSE_NOTIFY_REPLY;
req->in.h.nodeid = outarg->nodeid; req->in.h.nodeid = outarg->nodeid;
req->in.numargs = 2; req->in.numargs = 2;
req->in.argpages = 1; req->in.argpages = 1;
req->page_offset = offset; req->page_descs[0].offset = offset;
req->end = fuse_retrieve_end; req->end = fuse_retrieve_end;
index = outarg->offset >> PAGE_CACHE_SHIFT; index = outarg->offset >> PAGE_CACHE_SHIFT;
file_size = i_size_read(inode);
num = outarg->size;
if (outarg->offset > file_size)
num = 0;
else if (outarg->offset + num > file_size)
num = file_size - outarg->offset;
while (num && req->num_pages < FUSE_MAX_PAGES_PER_REQ) { while (num && req->num_pages < num_pages) {
struct page *page; struct page *page;
unsigned int this_num; unsigned int this_num;
...@@ -1568,6 +1631,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, ...@@ -1568,6 +1631,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset); this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
req->pages[req->num_pages] = page; req->pages[req->num_pages] = page;
req->page_descs[req->num_pages].length = this_num;
req->num_pages++; req->num_pages++;
offset = 0; offset = 0;
......
This diff is collapsed.
This diff is collapsed.
...@@ -44,6 +44,9 @@ ...@@ -44,6 +44,9 @@
doing the mount will be allowed to access the filesystem */ doing the mount will be allowed to access the filesystem */
#define FUSE_ALLOW_OTHER (1 << 1) #define FUSE_ALLOW_OTHER (1 << 1)
/** Number of page pointers embedded in fuse_req */
#define FUSE_REQ_INLINE_PAGES 1
/** List of active connections */ /** List of active connections */
extern struct list_head fuse_conn_list; extern struct list_head fuse_conn_list;
...@@ -103,6 +106,15 @@ struct fuse_inode { ...@@ -103,6 +106,15 @@ struct fuse_inode {
/** List of writepage requestst (pending or sent) */ /** List of writepage requestst (pending or sent) */
struct list_head writepages; struct list_head writepages;
/** Miscellaneous bits describing inode state */
unsigned long state;
};
/** FUSE inode state bits */
enum {
/** Advise readdirplus */
FUSE_I_ADVISE_RDPLUS,
}; };
struct fuse_conn; struct fuse_conn;
...@@ -200,6 +212,12 @@ struct fuse_out { ...@@ -200,6 +212,12 @@ struct fuse_out {
struct fuse_arg args[3]; struct fuse_arg args[3];
}; };
/** FUSE page descriptor */
struct fuse_page_desc {
unsigned int length;
unsigned int offset;
};
/** The request state */ /** The request state */
enum fuse_req_state { enum fuse_req_state {
FUSE_REQ_INIT = 0, FUSE_REQ_INIT = 0,
...@@ -291,14 +309,23 @@ struct fuse_req { ...@@ -291,14 +309,23 @@ struct fuse_req {
} misc; } misc;
/** page vector */ /** page vector */
struct page *pages[FUSE_MAX_PAGES_PER_REQ]; struct page **pages;
/** page-descriptor vector */
struct fuse_page_desc *page_descs;
/** size of the 'pages' array */
unsigned max_pages;
/** inline page vector */
struct page *inline_pages[FUSE_REQ_INLINE_PAGES];
/** inline page-descriptor vector */
struct fuse_page_desc inline_page_descs[FUSE_REQ_INLINE_PAGES];
/** number of pages in vector */ /** number of pages in vector */
unsigned num_pages; unsigned num_pages;
/** offset of data on first page */
unsigned page_offset;
/** File used in the request (or NULL) */ /** File used in the request (or NULL) */
struct fuse_file *ff; struct fuse_file *ff;
...@@ -487,6 +514,12 @@ struct fuse_conn { ...@@ -487,6 +514,12 @@ struct fuse_conn {
/** Use enhanced/automatic page cache invalidation. */ /** Use enhanced/automatic page cache invalidation. */
unsigned auto_inval_data:1; unsigned auto_inval_data:1;
/** Does the filesystem support readdirplus? */
unsigned do_readdirplus:1;
/** Does the filesystem want adaptive readdirplus? */
unsigned readdirplus_auto:1;
/** The number of requests waiting for completion */ /** The number of requests waiting for completion */
atomic_t num_waiting; atomic_t num_waiting;
...@@ -578,6 +611,9 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, ...@@ -578,6 +611,9 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
struct fuse_forget_link *fuse_alloc_forget(void); struct fuse_forget_link *fuse_alloc_forget(void);
/* Used by READDIRPLUS */
void fuse_force_forget(struct file *file, u64 nodeid);
/** /**
* Initialize READ or READDIR request * Initialize READ or READDIR request
*/ */
...@@ -658,9 +694,9 @@ void fuse_ctl_cleanup(void); ...@@ -658,9 +694,9 @@ void fuse_ctl_cleanup(void);
/** /**
* Allocate a request * Allocate a request
*/ */
struct fuse_req *fuse_request_alloc(void); struct fuse_req *fuse_request_alloc(unsigned npages);
struct fuse_req *fuse_request_alloc_nofs(void); struct fuse_req *fuse_request_alloc_nofs(unsigned npages);
/** /**
* Free a request * Free a request
...@@ -668,14 +704,25 @@ struct fuse_req *fuse_request_alloc_nofs(void); ...@@ -668,14 +704,25 @@ struct fuse_req *fuse_request_alloc_nofs(void);
void fuse_request_free(struct fuse_req *req); void fuse_request_free(struct fuse_req *req);
/** /**
* Get a request, may fail with -ENOMEM * Get a request, may fail with -ENOMEM,
* caller should specify # elements in req->pages[] explicitly
*/ */
struct fuse_req *fuse_get_req(struct fuse_conn *fc); struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages);
/**
* Get a request, may fail with -ENOMEM,
* useful for callers who doesn't use req->pages[]
*/
static inline struct fuse_req *fuse_get_req_nopages(struct fuse_conn *fc)
{
return fuse_get_req(fc, 0);
}
/** /**
* Gets a requests for a file operation, always succeeds * Gets a requests for a file operation, always succeeds
*/ */
struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file); struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc,
struct file *file);
/** /**
* Decrement reference count of a request. If count goes to zero free * Decrement reference count of a request. If count goes to zero free
...@@ -739,9 +786,9 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc); ...@@ -739,9 +786,9 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc);
int fuse_valid_type(int m); int fuse_valid_type(int m);
/** /**
* Is task allowed to perform filesystem operation? * Is current process allowed to perform filesystem operation?
*/ */
int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task); int fuse_allow_current_process(struct fuse_conn *fc);
u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id); u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id);
...@@ -776,8 +823,9 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, ...@@ -776,8 +823,9 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
bool isdir); bool isdir);
ssize_t fuse_direct_io(struct file *file, const char __user *buf, ssize_t fuse_direct_io(struct file *file, const struct iovec *iov,
size_t count, loff_t *ppos, int write); unsigned long nr_segs, size_t count, loff_t *ppos,
int write);
long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
unsigned int flags); unsigned int flags);
long fuse_ioctl_common(struct file *file, unsigned int cmd, long fuse_ioctl_common(struct file *file, unsigned int cmd,
......
...@@ -92,6 +92,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) ...@@ -92,6 +92,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
fi->attr_version = 0; fi->attr_version = 0;
fi->writectr = 0; fi->writectr = 0;
fi->orig_ino = 0; fi->orig_ino = 0;
fi->state = 0;
INIT_LIST_HEAD(&fi->write_files); INIT_LIST_HEAD(&fi->write_files);
INIT_LIST_HEAD(&fi->queued_writes); INIT_LIST_HEAD(&fi->queued_writes);
INIT_LIST_HEAD(&fi->writepages); INIT_LIST_HEAD(&fi->writepages);
...@@ -408,12 +409,12 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -408,12 +409,12 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
struct fuse_statfs_out outarg; struct fuse_statfs_out outarg;
int err; int err;
if (!fuse_allow_task(fc, current)) { if (!fuse_allow_current_process(fc)) {
buf->f_type = FUSE_SUPER_MAGIC; buf->f_type = FUSE_SUPER_MAGIC;
return 0; return 0;
} }
req = fuse_get_req(fc); req = fuse_get_req_nopages(fc);
if (IS_ERR(req)) if (IS_ERR(req))
return PTR_ERR(req); return PTR_ERR(req);
...@@ -863,6 +864,10 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) ...@@ -863,6 +864,10 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
fc->dont_mask = 1; fc->dont_mask = 1;
if (arg->flags & FUSE_AUTO_INVAL_DATA) if (arg->flags & FUSE_AUTO_INVAL_DATA)
fc->auto_inval_data = 1; fc->auto_inval_data = 1;
if (arg->flags & FUSE_DO_READDIRPLUS)
fc->do_readdirplus = 1;
if (arg->flags & FUSE_READDIRPLUS_AUTO)
fc->readdirplus_auto = 1;
} else { } else {
ra_pages = fc->max_read / PAGE_CACHE_SIZE; ra_pages = fc->max_read / PAGE_CACHE_SIZE;
fc->no_lock = 1; fc->no_lock = 1;
...@@ -889,7 +894,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) ...@@ -889,7 +894,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ | FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA; FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO;
req->in.h.opcode = FUSE_INIT; req->in.h.opcode = FUSE_INIT;
req->in.numargs = 1; req->in.numargs = 1;
req->in.args[0].size = sizeof(*arg); req->in.args[0].size = sizeof(*arg);
...@@ -1034,12 +1040,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1034,12 +1040,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
/* only now - we want root dentry with NULL ->d_op */ /* only now - we want root dentry with NULL ->d_op */
sb->s_d_op = &fuse_dentry_operations; sb->s_d_op = &fuse_dentry_operations;
init_req = fuse_request_alloc(); init_req = fuse_request_alloc(0);
if (!init_req) if (!init_req)
goto err_put_root; goto err_put_root;
if (is_bdev) { if (is_bdev) {
fc->destroy_req = fuse_request_alloc(); fc->destroy_req = fuse_request_alloc(0);
if (!fc->destroy_req) if (!fc->destroy_req)
goto err_free_init_req; goto err_free_init_req;
} }
......
...@@ -301,7 +301,7 @@ size_t iov_iter_copy_from_user(struct page *page, ...@@ -301,7 +301,7 @@ size_t iov_iter_copy_from_user(struct page *page,
struct iov_iter *i, unsigned long offset, size_t bytes); struct iov_iter *i, unsigned long offset, size_t bytes);
void iov_iter_advance(struct iov_iter *i, size_t bytes); void iov_iter_advance(struct iov_iter *i, size_t bytes);
int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes); int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes);
size_t iov_iter_single_seg_count(struct iov_iter *i); size_t iov_iter_single_seg_count(const struct iov_iter *i);
static inline void iov_iter_init(struct iov_iter *i, static inline void iov_iter_init(struct iov_iter *i,
const struct iovec *iov, unsigned long nr_segs, const struct iovec *iov, unsigned long nr_segs,
......
/* /*
FUSE: Filesystem in Userspace This file defines the kernel interface of FUSE
Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu> Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL. This program can be distributed under the terms of the GNU GPL.
See the file COPYING. See the file COPYING.
This -- and only this -- header file may also be distributed under
the terms of the BSD Licence as follows:
Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/ */
/* /*
...@@ -60,12 +86,25 @@ ...@@ -60,12 +86,25 @@
* *
* 7.20 * 7.20
* - add FUSE_AUTO_INVAL_DATA * - add FUSE_AUTO_INVAL_DATA
*
* 7.21
* - add FUSE_READDIRPLUS
* - send the requested events in POLL request
*/ */
#ifndef _LINUX_FUSE_H #ifndef _LINUX_FUSE_H
#define _LINUX_FUSE_H #define _LINUX_FUSE_H
#ifdef __linux__
#include <linux/types.h> #include <linux/types.h>
#else
#include <stdint.h>
#define __u64 uint64_t
#define __s64 int64_t
#define __u32 uint32_t
#define __s32 int32_t
#define __u16 uint16_t
#endif
/* /*
* Version negotiation: * Version negotiation:
...@@ -91,7 +130,7 @@ ...@@ -91,7 +130,7 @@
#define FUSE_KERNEL_VERSION 7 #define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */ /** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 20 #define FUSE_KERNEL_MINOR_VERSION 21
/** The node ID of the root inode */ /** The node ID of the root inode */
#define FUSE_ROOT_ID 1 #define FUSE_ROOT_ID 1
...@@ -179,6 +218,8 @@ struct fuse_file_lock { ...@@ -179,6 +218,8 @@ struct fuse_file_lock {
* FUSE_FLOCK_LOCKS: remote locking for BSD style file locks * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks
* FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories
* FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages
* FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one)
* FUSE_READDIRPLUS_AUTO: adaptive readdirplus
*/ */
#define FUSE_ASYNC_READ (1 << 0) #define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1) #define FUSE_POSIX_LOCKS (1 << 1)
...@@ -193,6 +234,8 @@ struct fuse_file_lock { ...@@ -193,6 +234,8 @@ struct fuse_file_lock {
#define FUSE_FLOCK_LOCKS (1 << 10) #define FUSE_FLOCK_LOCKS (1 << 10)
#define FUSE_HAS_IOCTL_DIR (1 << 11) #define FUSE_HAS_IOCTL_DIR (1 << 11)
#define FUSE_AUTO_INVAL_DATA (1 << 12) #define FUSE_AUTO_INVAL_DATA (1 << 12)
#define FUSE_DO_READDIRPLUS (1 << 13)
#define FUSE_READDIRPLUS_AUTO (1 << 14)
/** /**
* CUSE INIT request/reply flags * CUSE INIT request/reply flags
...@@ -299,6 +342,7 @@ enum fuse_opcode { ...@@ -299,6 +342,7 @@ enum fuse_opcode {
FUSE_NOTIFY_REPLY = 41, FUSE_NOTIFY_REPLY = 41,
FUSE_BATCH_FORGET = 42, FUSE_BATCH_FORGET = 42,
FUSE_FALLOCATE = 43, FUSE_FALLOCATE = 43,
FUSE_READDIRPLUS = 44,
/* CUSE specific operations */ /* CUSE specific operations */
CUSE_INIT = 4096, CUSE_INIT = 4096,
...@@ -580,7 +624,7 @@ struct fuse_poll_in { ...@@ -580,7 +624,7 @@ struct fuse_poll_in {
__u64 fh; __u64 fh;
__u64 kh; __u64 kh;
__u32 flags; __u32 flags;
__u32 padding; __u32 events;
}; };
struct fuse_poll_out { struct fuse_poll_out {
...@@ -630,6 +674,16 @@ struct fuse_dirent { ...@@ -630,6 +674,16 @@ struct fuse_dirent {
#define FUSE_DIRENT_SIZE(d) \ #define FUSE_DIRENT_SIZE(d) \
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
struct fuse_direntplus {
struct fuse_entry_out entry_out;
struct fuse_dirent dirent;
};
#define FUSE_NAME_OFFSET_DIRENTPLUS \
offsetof(struct fuse_direntplus, dirent.name)
#define FUSE_DIRENTPLUS_SIZE(d) \
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen)
struct fuse_notify_inval_inode_out { struct fuse_notify_inval_inode_out {
__u64 ino; __u64 ino;
__s64 off; __s64 off;
......
...@@ -2056,7 +2056,7 @@ EXPORT_SYMBOL(iov_iter_fault_in_readable); ...@@ -2056,7 +2056,7 @@ EXPORT_SYMBOL(iov_iter_fault_in_readable);
/* /*
* Return the count of just the current iov_iter segment. * Return the count of just the current iov_iter segment.
*/ */
size_t iov_iter_single_seg_count(struct iov_iter *i) size_t iov_iter_single_seg_count(const struct iov_iter *i)
{ {
const struct iovec *iov = i->iov; const struct iovec *iov = i->iov;
if (i->nr_segs == 1) if (i->nr_segs == 1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment