mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse fixes from Miklos Szeredi: "One patch fixes an Oops introduced in 3.9 with the readdirplus feature. The rest are fixes for async-dio in 3.10" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: fuse: fix alignment in short read optimization for async_dio fuse: return -EIOCBQUEUED from fuse_direct_IO() for all async requests fuse: fix readdirplus Oops in fuse_dentry_revalidate fuse: update inode size and invalidate attributes on fallocate fuse: truncate pagecache range on hole punch fuse: allocate for_background dio requests based on io->async state
This commit is contained in:
commit
8764d86100
|
@ -180,6 +180,8 @@ u64 fuse_get_attr_version(struct fuse_conn *fc)
|
||||||
static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
|
static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
struct dentry *parent;
|
||||||
|
struct fuse_conn *fc;
|
||||||
|
|
||||||
inode = ACCESS_ONCE(entry->d_inode);
|
inode = ACCESS_ONCE(entry->d_inode);
|
||||||
if (inode && is_bad_inode(inode))
|
if (inode && is_bad_inode(inode))
|
||||||
|
@ -187,10 +189,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
|
||||||
else if (fuse_dentry_time(entry) < get_jiffies_64()) {
|
else if (fuse_dentry_time(entry) < get_jiffies_64()) {
|
||||||
int err;
|
int err;
|
||||||
struct fuse_entry_out outarg;
|
struct fuse_entry_out outarg;
|
||||||
struct fuse_conn *fc;
|
|
||||||
struct fuse_req *req;
|
struct fuse_req *req;
|
||||||
struct fuse_forget_link *forget;
|
struct fuse_forget_link *forget;
|
||||||
struct dentry *parent;
|
|
||||||
u64 attr_version;
|
u64 attr_version;
|
||||||
|
|
||||||
/* For negative dentries, always do a fresh lookup */
|
/* For negative dentries, always do a fresh lookup */
|
||||||
|
@ -241,8 +241,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
|
||||||
entry_attr_timeout(&outarg),
|
entry_attr_timeout(&outarg),
|
||||||
attr_version);
|
attr_version);
|
||||||
fuse_change_entry_timeout(entry, &outarg);
|
fuse_change_entry_timeout(entry, &outarg);
|
||||||
|
} else if (inode) {
|
||||||
|
fc = get_fuse_conn(inode);
|
||||||
|
if (fc->readdirplus_auto) {
|
||||||
|
parent = dget_parent(entry);
|
||||||
|
fuse_advise_use_readdirplus(parent->d_inode);
|
||||||
|
dput(parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fuse_advise_use_readdirplus(inode);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/swap.h>
|
#include <linux/swap.h>
|
||||||
#include <linux/aio.h>
|
#include <linux/aio.h>
|
||||||
|
#include <linux/falloc.h>
|
||||||
|
|
||||||
static const struct file_operations fuse_direct_io_file_operations;
|
static const struct file_operations fuse_direct_io_file_operations;
|
||||||
|
|
||||||
|
@ -1278,7 +1279,10 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,
|
||||||
|
|
||||||
iov_iter_init(&ii, iov, nr_segs, count, 0);
|
iov_iter_init(&ii, iov, nr_segs, count, 0);
|
||||||
|
|
||||||
req = fuse_get_req(fc, fuse_iter_npages(&ii));
|
if (io->async)
|
||||||
|
req = fuse_get_req_for_background(fc, fuse_iter_npages(&ii));
|
||||||
|
else
|
||||||
|
req = fuse_get_req(fc, fuse_iter_npages(&ii));
|
||||||
if (IS_ERR(req))
|
if (IS_ERR(req))
|
||||||
return PTR_ERR(req);
|
return PTR_ERR(req);
|
||||||
|
|
||||||
|
@ -1314,7 +1318,11 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,
|
||||||
break;
|
break;
|
||||||
if (count) {
|
if (count) {
|
||||||
fuse_put_request(fc, req);
|
fuse_put_request(fc, req);
|
||||||
req = fuse_get_req(fc, fuse_iter_npages(&ii));
|
if (io->async)
|
||||||
|
req = fuse_get_req_for_background(fc,
|
||||||
|
fuse_iter_npages(&ii));
|
||||||
|
else
|
||||||
|
req = fuse_get_req(fc, fuse_iter_npages(&ii));
|
||||||
if (IS_ERR(req))
|
if (IS_ERR(req))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2365,6 +2373,11 @@ static void fuse_do_truncate(struct file *file)
|
||||||
fuse_do_setattr(inode, &attr, file);
|
fuse_do_setattr(inode, &attr, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline loff_t fuse_round_up(loff_t off)
|
||||||
|
{
|
||||||
|
return round_up(off, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||||||
loff_t offset, unsigned long nr_segs)
|
loff_t offset, unsigned long nr_segs)
|
||||||
|
@ -2372,6 +2385,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
struct file *file = iocb->ki_filp;
|
struct file *file = iocb->ki_filp;
|
||||||
struct fuse_file *ff = file->private_data;
|
struct fuse_file *ff = file->private_data;
|
||||||
|
bool async_dio = ff->fc->async_dio;
|
||||||
loff_t pos = 0;
|
loff_t pos = 0;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
loff_t i_size;
|
loff_t i_size;
|
||||||
|
@ -2383,10 +2397,10 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||||||
i_size = i_size_read(inode);
|
i_size = i_size_read(inode);
|
||||||
|
|
||||||
/* optimization for short read */
|
/* optimization for short read */
|
||||||
if (rw != WRITE && offset + count > i_size) {
|
if (async_dio && rw != WRITE && offset + count > i_size) {
|
||||||
if (offset >= i_size)
|
if (offset >= i_size)
|
||||||
return 0;
|
return 0;
|
||||||
count = i_size - offset;
|
count = min_t(loff_t, count, fuse_round_up(i_size - offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
|
io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
|
||||||
|
@ -2404,7 +2418,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||||||
* By default, we want to optimize all I/Os with async request
|
* By default, we want to optimize all I/Os with async request
|
||||||
* submission to the client filesystem if supported.
|
* submission to the client filesystem if supported.
|
||||||
*/
|
*/
|
||||||
io->async = ff->fc->async_dio;
|
io->async = async_dio;
|
||||||
io->iocb = iocb;
|
io->iocb = iocb;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2412,7 +2426,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||||||
* to wait on real async I/O requests, so we must submit this request
|
* to wait on real async I/O requests, so we must submit this request
|
||||||
* synchronously.
|
* synchronously.
|
||||||
*/
|
*/
|
||||||
if (!is_sync_kiocb(iocb) && (offset + count > i_size))
|
if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE)
|
||||||
io->async = false;
|
io->async = false;
|
||||||
|
|
||||||
if (rw == WRITE)
|
if (rw == WRITE)
|
||||||
|
@ -2424,7 +2438,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||||||
fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
|
fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
|
||||||
|
|
||||||
/* we have a non-extending, async request, so return */
|
/* we have a non-extending, async request, so return */
|
||||||
if (ret > 0 && !is_sync_kiocb(iocb))
|
if (!is_sync_kiocb(iocb))
|
||||||
return -EIOCBQUEUED;
|
return -EIOCBQUEUED;
|
||||||
|
|
||||||
ret = wait_on_sync_kiocb(iocb);
|
ret = wait_on_sync_kiocb(iocb);
|
||||||
|
@ -2446,6 +2460,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
|
||||||
loff_t length)
|
loff_t length)
|
||||||
{
|
{
|
||||||
struct fuse_file *ff = file->private_data;
|
struct fuse_file *ff = file->private_data;
|
||||||
|
struct inode *inode = file->f_inode;
|
||||||
struct fuse_conn *fc = ff->fc;
|
struct fuse_conn *fc = ff->fc;
|
||||||
struct fuse_req *req;
|
struct fuse_req *req;
|
||||||
struct fuse_fallocate_in inarg = {
|
struct fuse_fallocate_in inarg = {
|
||||||
|
@ -2459,9 +2474,16 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
|
||||||
if (fc->no_fallocate)
|
if (fc->no_fallocate)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (mode & FALLOC_FL_PUNCH_HOLE) {
|
||||||
|
mutex_lock(&inode->i_mutex);
|
||||||
|
fuse_set_nowrite(inode);
|
||||||
|
}
|
||||||
|
|
||||||
req = fuse_get_req_nopages(fc);
|
req = fuse_get_req_nopages(fc);
|
||||||
if (IS_ERR(req))
|
if (IS_ERR(req)) {
|
||||||
return PTR_ERR(req);
|
err = PTR_ERR(req);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
req->in.h.opcode = FUSE_FALLOCATE;
|
req->in.h.opcode = FUSE_FALLOCATE;
|
||||||
req->in.h.nodeid = ff->nodeid;
|
req->in.h.nodeid = ff->nodeid;
|
||||||
|
@ -2476,6 +2498,24 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
|
||||||
}
|
}
|
||||||
fuse_put_request(fc, req);
|
fuse_put_request(fc, req);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* we could have extended the file */
|
||||||
|
if (!(mode & FALLOC_FL_KEEP_SIZE))
|
||||||
|
fuse_write_update_size(inode, offset + length);
|
||||||
|
|
||||||
|
if (mode & FALLOC_FL_PUNCH_HOLE)
|
||||||
|
truncate_pagecache_range(inode, offset, offset + length - 1);
|
||||||
|
|
||||||
|
fuse_invalidate_attr(inode);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (mode & FALLOC_FL_PUNCH_HOLE) {
|
||||||
|
fuse_release_nowrite(inode);
|
||||||
|
mutex_unlock(&inode->i_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -867,10 +867,11 @@ 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)
|
if (arg->flags & FUSE_DO_READDIRPLUS) {
|
||||||
fc->do_readdirplus = 1;
|
fc->do_readdirplus = 1;
|
||||||
if (arg->flags & FUSE_READDIRPLUS_AUTO)
|
if (arg->flags & FUSE_READDIRPLUS_AUTO)
|
||||||
fc->readdirplus_auto = 1;
|
fc->readdirplus_auto = 1;
|
||||||
|
}
|
||||||
if (arg->flags & FUSE_ASYNC_DIO)
|
if (arg->flags & FUSE_ASYNC_DIO)
|
||||||
fc->async_dio = 1;
|
fc->async_dio = 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue