Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions fs/fuse/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,7 @@ static void fuse_dio_lock(struct kiocb *iocb, struct iov_iter *from,
bool *exclusive)
{
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);
if (*exclusive) {
Expand All @@ -1445,7 +1445,7 @@ static void fuse_dio_lock(struct kiocb *iocb, struct iov_iter *from,
* have raced, so check it again.
*/
if (fuse_io_past_eof(iocb, from) ||
fuse_file_uncached_io_start(inode, ff) != 0) {
fuse_inode_uncached_io_start(fi) != 0) {
inode_unlock_shared(inode);
inode_lock(inode);
*exclusive = true;
Expand All @@ -1456,13 +1456,13 @@ static void fuse_dio_lock(struct kiocb *iocb, struct iov_iter *from,
static void fuse_dio_unlock(struct kiocb *iocb, bool exclusive)
{
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) {
inode_unlock(inode);
} else {
/* 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);
}
}
Expand Down
2 changes: 2 additions & 0 deletions fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1465,6 +1465,8 @@ int fuse_fileattr_set(struct mnt_idmap *idmap,

/* iomode.c */
int fuse_file_cached_io_start(struct inode *inode, struct fuse_file *ff);
int fuse_inode_uncached_io_start(struct fuse_inode *fi);
void fuse_inode_uncached_io_end(struct fuse_inode *fi);
int fuse_file_uncached_io_start(struct inode *inode, struct fuse_file *ff);
void fuse_file_uncached_io_end(struct inode *inode, struct fuse_file *ff);

Expand Down
3 changes: 3 additions & 0 deletions fs/fuse/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ static void fuse_evict_inode(struct inode *inode)
fuse_cleanup_submount_lookup(fc, fi->submount_lookup);
fi->submount_lookup = NULL;
}
if (S_ISREG(inode->i_mode) && !fuse_is_bad(inode)) {
WARN_ON(fi->iocachectr != 0);
}
/*
* Evict of non-deleted inode may race with outstanding
* LOOKUP/READDIRPLUS requests and result in inconsistency when
Expand Down
51 changes: 41 additions & 10 deletions fs/fuse/iomode.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,39 +70,70 @@ static void fuse_file_cached_io_end(struct inode *inode, struct fuse_file *ff)
spin_unlock(&fi->lock);
}

/* Start strictly uncached io mode where cache access is not allowed */
int fuse_file_uncached_io_start(struct inode *inode, struct fuse_file *ff)
/*
* Start strictly uncached io mode where cache access is not allowed.
* This is for parallel DIO - does NOT change ff->iomode state.
*/
int fuse_inode_uncached_io_start(struct fuse_inode *fi)
{
struct fuse_inode *fi = get_fuse_inode(inode);
int err = 0;

spin_lock(&fi->lock);
if (fi->iocachectr > 0) {
err = -ETXTBSY;
goto unlock;
}
WARN_ON(ff->iomode != IOM_NONE);
fi->iocachectr--;
ff->iomode = IOM_UNCACHED;
unlock:
spin_unlock(&fi->lock);
return err;
}

void fuse_file_uncached_io_end(struct inode *inode, struct fuse_file *ff)
/*
* End uncached io mode for parallel DIO.
* Does NOT change ff->iomode state.
*/
void fuse_inode_uncached_io_end(struct fuse_inode *fi)
{
struct fuse_inode *fi = get_fuse_inode(inode);

spin_lock(&fi->lock);
WARN_ON(fi->iocachectr >= 0);
WARN_ON(ff->iomode != IOM_UNCACHED);
ff->iomode = IOM_NONE;
fi->iocachectr++;
if (!fi->iocachectr)
wake_up(&fi->direct_io_waitq);
spin_unlock(&fi->lock);
}

/*
* Start uncached io mode for file open.
* Takes uncached_io inode mode reference AND sets ff->iomode.
*/
int fuse_file_uncached_io_start(struct inode *inode, struct fuse_file *ff)
{
struct fuse_inode *fi = get_fuse_inode(inode);
int err;

err = fuse_inode_uncached_io_start(fi);
if (err)
return err;

WARN_ON(ff->iomode != IOM_NONE);
ff->iomode = IOM_UNCACHED;
return 0;
}

/*
* End uncached io mode for file release.
* Drops uncached_io inode mode reference AND clears ff->iomode.
*/
void fuse_file_uncached_io_end(struct inode *inode, struct fuse_file *ff)
{
struct fuse_inode *fi = get_fuse_inode(inode);

WARN_ON(ff->iomode != IOM_UNCACHED);
ff->iomode = IOM_NONE;
fuse_inode_uncached_io_end(fi);
}

/* Request access to submit new io to inode via open file */
int fuse_file_io_open(struct file *file, struct inode *inode)
{
Expand Down