fuse fixes for 6.9-rc5
-----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQSQHSd0lITzzeNWNm3h3BK/laaZPAUCZiJcTAAKCRDh3BK/laaZ PK1QAP9u/S7GYKDj0k58xOVAof2x/q0puHWXoObRma+bPmeoeQEA2+K+vlnTJHub kLRURaTCzGyFfL+CB/JQ4Kv4tDF5qQc= =Eoob -----END PGP SIGNATURE----- Merge tag 'fuse-fixes-6.9-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse Pull fuse fixes from Miklos Szeredi: - Fix two bugs in the new passthrough mode - Fix a statx bug introduced in v6.6 - Fix code documentation * tag 'fuse-fixes-6.9-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: cuse: add kernel-doc comments to cuse_process_init_reply() fuse: fix leaked ENOSYS error on first statx call fuse: fix parallel dio write on file open in passthrough mode fuse: fix wrong ff->iomode state changes from parallel dio write
This commit is contained in:
commit
daa757767d
@ -310,6 +310,10 @@ struct cuse_init_args {
|
|||||||
/**
|
/**
|
||||||
* cuse_process_init_reply - finish initializing CUSE channel
|
* cuse_process_init_reply - finish initializing CUSE channel
|
||||||
*
|
*
|
||||||
|
* @fm: The fuse mount information containing the CUSE connection.
|
||||||
|
* @args: The arguments passed to the init reply.
|
||||||
|
* @error: The error code signifying if any error occurred during the process.
|
||||||
|
*
|
||||||
* This function creates the character device and sets up all the
|
* This function creates the character device and sets up all the
|
||||||
* required data structures for it. Please read the comment at the
|
* required data structures for it. Please read the comment at the
|
||||||
* top of this file for high level overview.
|
* top of this file for high level overview.
|
||||||
|
@ -1321,6 +1321,7 @@ retry:
|
|||||||
err = fuse_do_statx(inode, file, stat);
|
err = fuse_do_statx(inode, file, stat);
|
||||||
if (err == -ENOSYS) {
|
if (err == -ENOSYS) {
|
||||||
fc->no_statx = 1;
|
fc->no_statx = 1;
|
||||||
|
err = 0;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1362,7 +1362,7 @@ static void fuse_dio_lock(struct kiocb *iocb, struct iov_iter *from,
|
|||||||
bool *exclusive)
|
bool *exclusive)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(iocb->ki_filp);
|
struct inode *inode = file_inode(iocb->ki_filp);
|
||||||
struct fuse_file *ff = iocb->ki_filp->private_data;
|
struct fuse_inode *fi = get_fuse_inode(inode);
|
||||||
|
|
||||||
*exclusive = fuse_dio_wr_exclusive_lock(iocb, from);
|
*exclusive = fuse_dio_wr_exclusive_lock(iocb, from);
|
||||||
if (*exclusive) {
|
if (*exclusive) {
|
||||||
@ -1377,7 +1377,7 @@ static void fuse_dio_lock(struct kiocb *iocb, struct iov_iter *from,
|
|||||||
* have raced, so check it again.
|
* have raced, so check it again.
|
||||||
*/
|
*/
|
||||||
if (fuse_io_past_eof(iocb, from) ||
|
if (fuse_io_past_eof(iocb, from) ||
|
||||||
fuse_file_uncached_io_start(inode, ff, NULL) != 0) {
|
fuse_inode_uncached_io_start(fi, NULL) != 0) {
|
||||||
inode_unlock_shared(inode);
|
inode_unlock_shared(inode);
|
||||||
inode_lock(inode);
|
inode_lock(inode);
|
||||||
*exclusive = true;
|
*exclusive = true;
|
||||||
@ -1388,13 +1388,13 @@ static void fuse_dio_lock(struct kiocb *iocb, struct iov_iter *from,
|
|||||||
static void fuse_dio_unlock(struct kiocb *iocb, bool exclusive)
|
static void fuse_dio_unlock(struct kiocb *iocb, bool exclusive)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(iocb->ki_filp);
|
struct inode *inode = file_inode(iocb->ki_filp);
|
||||||
struct fuse_file *ff = iocb->ki_filp->private_data;
|
struct fuse_inode *fi = get_fuse_inode(inode);
|
||||||
|
|
||||||
if (exclusive) {
|
if (exclusive) {
|
||||||
inode_unlock(inode);
|
inode_unlock(inode);
|
||||||
} else {
|
} else {
|
||||||
/* Allow opens in caching mode after last parallel dio end */
|
/* Allow opens in caching mode after last parallel dio end */
|
||||||
fuse_file_uncached_io_end(inode, ff);
|
fuse_inode_uncached_io_end(fi);
|
||||||
inode_unlock_shared(inode);
|
inode_unlock_shared(inode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2574,8 +2574,10 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
|
|||||||
* First mmap of direct_io file enters caching inode io mode.
|
* First mmap of direct_io file enters caching inode io mode.
|
||||||
* Also waits for parallel dio writers to go into serial mode
|
* Also waits for parallel dio writers to go into serial mode
|
||||||
* (exclusive instead of shared lock).
|
* (exclusive instead of shared lock).
|
||||||
|
* After first mmap, the inode stays in caching io mode until
|
||||||
|
* the direct_io file release.
|
||||||
*/
|
*/
|
||||||
rc = fuse_file_cached_io_start(inode, ff);
|
rc = fuse_file_cached_io_open(inode, ff);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1394,9 +1394,10 @@ int fuse_fileattr_set(struct mnt_idmap *idmap,
|
|||||||
struct dentry *dentry, struct fileattr *fa);
|
struct dentry *dentry, struct fileattr *fa);
|
||||||
|
|
||||||
/* iomode.c */
|
/* iomode.c */
|
||||||
int fuse_file_cached_io_start(struct inode *inode, struct fuse_file *ff);
|
int fuse_file_cached_io_open(struct inode *inode, struct fuse_file *ff);
|
||||||
int fuse_file_uncached_io_start(struct inode *inode, struct fuse_file *ff, struct fuse_backing *fb);
|
int fuse_inode_uncached_io_start(struct fuse_inode *fi,
|
||||||
void fuse_file_uncached_io_end(struct inode *inode, struct fuse_file *ff);
|
struct fuse_backing *fb);
|
||||||
|
void fuse_inode_uncached_io_end(struct fuse_inode *fi);
|
||||||
|
|
||||||
int fuse_file_io_open(struct file *file, struct inode *inode);
|
int fuse_file_io_open(struct file *file, struct inode *inode);
|
||||||
void fuse_file_io_release(struct fuse_file *ff, struct inode *inode);
|
void fuse_file_io_release(struct fuse_file *ff, struct inode *inode);
|
||||||
|
@ -175,6 +175,7 @@ static void fuse_evict_inode(struct inode *inode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (S_ISREG(inode->i_mode) && !fuse_is_bad(inode)) {
|
if (S_ISREG(inode->i_mode) && !fuse_is_bad(inode)) {
|
||||||
|
WARN_ON(fi->iocachectr != 0);
|
||||||
WARN_ON(!list_empty(&fi->write_files));
|
WARN_ON(!list_empty(&fi->write_files));
|
||||||
WARN_ON(!list_empty(&fi->queued_writes));
|
WARN_ON(!list_empty(&fi->queued_writes));
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,13 @@ static inline bool fuse_is_io_cache_wait(struct fuse_inode *fi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start cached io mode.
|
* Called on cached file open() and on first mmap() of direct_io file.
|
||||||
|
* Takes cached_io inode mode reference to be dropped on file release.
|
||||||
*
|
*
|
||||||
* Blocks new parallel dio writes and waits for the in-progress parallel dio
|
* Blocks new parallel dio writes and waits for the in-progress parallel dio
|
||||||
* writes to complete.
|
* writes to complete.
|
||||||
*/
|
*/
|
||||||
int fuse_file_cached_io_start(struct inode *inode, struct fuse_file *ff)
|
int fuse_file_cached_io_open(struct inode *inode, struct fuse_file *ff)
|
||||||
{
|
{
|
||||||
struct fuse_inode *fi = get_fuse_inode(inode);
|
struct fuse_inode *fi = get_fuse_inode(inode);
|
||||||
|
|
||||||
@ -67,10 +68,9 @@ int fuse_file_cached_io_start(struct inode *inode, struct fuse_file *ff)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fuse_file_cached_io_end(struct inode *inode, struct fuse_file *ff)
|
static void fuse_file_cached_io_release(struct fuse_file *ff,
|
||||||
|
struct fuse_inode *fi)
|
||||||
{
|
{
|
||||||
struct fuse_inode *fi = get_fuse_inode(inode);
|
|
||||||
|
|
||||||
spin_lock(&fi->lock);
|
spin_lock(&fi->lock);
|
||||||
WARN_ON(fi->iocachectr <= 0);
|
WARN_ON(fi->iocachectr <= 0);
|
||||||
WARN_ON(ff->iomode != IOM_CACHED);
|
WARN_ON(ff->iomode != IOM_CACHED);
|
||||||
@ -82,16 +82,15 @@ static void fuse_file_cached_io_end(struct inode *inode, struct fuse_file *ff)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Start strictly uncached io mode where cache access is not allowed */
|
/* Start strictly uncached io mode where cache access is not allowed */
|
||||||
int fuse_file_uncached_io_start(struct inode *inode, struct fuse_file *ff, struct fuse_backing *fb)
|
int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb)
|
||||||
{
|
{
|
||||||
struct fuse_inode *fi = get_fuse_inode(inode);
|
|
||||||
struct fuse_backing *oldfb;
|
struct fuse_backing *oldfb;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
spin_lock(&fi->lock);
|
spin_lock(&fi->lock);
|
||||||
/* deny conflicting backing files on same fuse inode */
|
/* deny conflicting backing files on same fuse inode */
|
||||||
oldfb = fuse_inode_backing(fi);
|
oldfb = fuse_inode_backing(fi);
|
||||||
if (oldfb && oldfb != fb) {
|
if (fb && oldfb && oldfb != fb) {
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
@ -99,12 +98,10 @@ int fuse_file_uncached_io_start(struct inode *inode, struct fuse_file *ff, struc
|
|||||||
err = -ETXTBSY;
|
err = -ETXTBSY;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
WARN_ON(ff->iomode != IOM_NONE);
|
|
||||||
fi->iocachectr--;
|
fi->iocachectr--;
|
||||||
ff->iomode = IOM_UNCACHED;
|
|
||||||
|
|
||||||
/* fuse inode holds a single refcount of backing file */
|
/* fuse inode holds a single refcount of backing file */
|
||||||
if (!oldfb) {
|
if (fb && !oldfb) {
|
||||||
oldfb = fuse_inode_backing_set(fi, fb);
|
oldfb = fuse_inode_backing_set(fi, fb);
|
||||||
WARN_ON_ONCE(oldfb != NULL);
|
WARN_ON_ONCE(oldfb != NULL);
|
||||||
} else {
|
} else {
|
||||||
@ -115,15 +112,29 @@ unlock:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_file_uncached_io_end(struct inode *inode, struct fuse_file *ff)
|
/* Takes uncached_io inode mode reference to be dropped on file release */
|
||||||
|
static int fuse_file_uncached_io_open(struct inode *inode,
|
||||||
|
struct fuse_file *ff,
|
||||||
|
struct fuse_backing *fb)
|
||||||
{
|
{
|
||||||
struct fuse_inode *fi = get_fuse_inode(inode);
|
struct fuse_inode *fi = get_fuse_inode(inode);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = fuse_inode_uncached_io_start(fi, fb);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
WARN_ON(ff->iomode != IOM_NONE);
|
||||||
|
ff->iomode = IOM_UNCACHED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fuse_inode_uncached_io_end(struct fuse_inode *fi)
|
||||||
|
{
|
||||||
struct fuse_backing *oldfb = NULL;
|
struct fuse_backing *oldfb = NULL;
|
||||||
|
|
||||||
spin_lock(&fi->lock);
|
spin_lock(&fi->lock);
|
||||||
WARN_ON(fi->iocachectr >= 0);
|
WARN_ON(fi->iocachectr >= 0);
|
||||||
WARN_ON(ff->iomode != IOM_UNCACHED);
|
|
||||||
ff->iomode = IOM_NONE;
|
|
||||||
fi->iocachectr++;
|
fi->iocachectr++;
|
||||||
if (!fi->iocachectr) {
|
if (!fi->iocachectr) {
|
||||||
wake_up(&fi->direct_io_waitq);
|
wake_up(&fi->direct_io_waitq);
|
||||||
@ -134,6 +145,15 @@ void fuse_file_uncached_io_end(struct inode *inode, struct fuse_file *ff)
|
|||||||
fuse_backing_put(oldfb);
|
fuse_backing_put(oldfb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Drop uncached_io reference from passthrough open */
|
||||||
|
static void fuse_file_uncached_io_release(struct fuse_file *ff,
|
||||||
|
struct fuse_inode *fi)
|
||||||
|
{
|
||||||
|
WARN_ON(ff->iomode != IOM_UNCACHED);
|
||||||
|
ff->iomode = IOM_NONE;
|
||||||
|
fuse_inode_uncached_io_end(fi);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open flags that are allowed in combination with FOPEN_PASSTHROUGH.
|
* Open flags that are allowed in combination with FOPEN_PASSTHROUGH.
|
||||||
* A combination of FOPEN_PASSTHROUGH and FOPEN_DIRECT_IO means that read/write
|
* A combination of FOPEN_PASSTHROUGH and FOPEN_DIRECT_IO means that read/write
|
||||||
@ -163,7 +183,7 @@ static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
|
|||||||
return PTR_ERR(fb);
|
return PTR_ERR(fb);
|
||||||
|
|
||||||
/* First passthrough file open denies caching inode io mode */
|
/* First passthrough file open denies caching inode io mode */
|
||||||
err = fuse_file_uncached_io_start(inode, ff, fb);
|
err = fuse_file_uncached_io_open(inode, ff, fb);
|
||||||
if (!err)
|
if (!err)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -216,7 +236,7 @@ int fuse_file_io_open(struct file *file, struct inode *inode)
|
|||||||
if (ff->open_flags & FOPEN_PASSTHROUGH)
|
if (ff->open_flags & FOPEN_PASSTHROUGH)
|
||||||
err = fuse_file_passthrough_open(inode, file);
|
err = fuse_file_passthrough_open(inode, file);
|
||||||
else
|
else
|
||||||
err = fuse_file_cached_io_start(inode, ff);
|
err = fuse_file_cached_io_open(inode, ff);
|
||||||
if (err)
|
if (err)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
@ -236,8 +256,10 @@ fail:
|
|||||||
/* No more pending io and no new io possible to inode via open/mmapped file */
|
/* No more pending io and no new io possible to inode via open/mmapped file */
|
||||||
void fuse_file_io_release(struct fuse_file *ff, struct inode *inode)
|
void fuse_file_io_release(struct fuse_file *ff, struct inode *inode)
|
||||||
{
|
{
|
||||||
|
struct fuse_inode *fi = get_fuse_inode(inode);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Last parallel dio close allows caching inode io mode.
|
* Last passthrough file close allows caching inode io mode.
|
||||||
* Last caching file close exits caching inode io mode.
|
* Last caching file close exits caching inode io mode.
|
||||||
*/
|
*/
|
||||||
switch (ff->iomode) {
|
switch (ff->iomode) {
|
||||||
@ -245,10 +267,10 @@ void fuse_file_io_release(struct fuse_file *ff, struct inode *inode)
|
|||||||
/* Nothing to do */
|
/* Nothing to do */
|
||||||
break;
|
break;
|
||||||
case IOM_UNCACHED:
|
case IOM_UNCACHED:
|
||||||
fuse_file_uncached_io_end(inode, ff);
|
fuse_file_uncached_io_release(ff, fi);
|
||||||
break;
|
break;
|
||||||
case IOM_CACHED:
|
case IOM_CACHED:
|
||||||
fuse_file_cached_io_end(inode, ff);
|
fuse_file_cached_io_release(ff, fi);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user