Skip to content

Commit cdd39b0

Browse files
committed
Merge tag 'fuse-update-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse updates from Miklos Szeredi: - Fix a possible of deadlock in case inode writeback is in progress during dentry reclaim - Fix a crash in case of page stealing - Selectively invalidate cached attributes, possibly improving performance - Allow filesystems to disable data flushing from ->flush() - Misc fixes and cleanups * tag 'fuse-update-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (23 commits) fuse: fix page stealing virtiofs: use strscpy for copying the queue name fuse: add FOPEN_NOFLUSH fuse: only update necessary attributes fuse: take cache_mask into account in getattr fuse: add cache_mask fuse: move reverting attributes to fuse_change_attributes() fuse: simplify local variables holding writeback cache state fuse: cleanup code conditional on fc->writeback_cache fuse: fix attr version comparison in fuse_read_update_size() fuse: always invalidate attributes after writes fuse: rename fuse_write_update_size() fuse: don't bump attr_version in cached write fuse: selective attribute invalidation fuse: don't increment nlink in link() fuse: decrement nlink on overwriting rename fuse: simplify __fuse_write_file_get() fuse: move fuse_invalidate_attr() into fuse_update_ctime() fuse: delete redundant code fuse: use kmap_local_page() ...
2 parents a0c7d4a + 712a951 commit cdd39b0

File tree

11 files changed

+203
-151
lines changed

11 files changed

+203
-151
lines changed

fs/fuse/dax.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -732,11 +732,8 @@ static ssize_t fuse_dax_direct_write(struct kiocb *iocb, struct iov_iter *from)
732732
ssize_t ret;
733733

734734
ret = fuse_direct_io(&io, from, &iocb->ki_pos, FUSE_DIO_WRITE);
735-
if (ret < 0)
736-
return ret;
737735

738-
fuse_invalidate_attr(inode);
739-
fuse_write_update_size(inode, iocb->ki_pos);
736+
fuse_write_update_attr(inode, iocb->ki_pos, ret);
740737
return ret;
741738
}
742739

fs/fuse/dev.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -756,15 +756,15 @@ static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size)
756756
{
757757
unsigned ncpy = min(*size, cs->len);
758758
if (val) {
759-
void *pgaddr = kmap_atomic(cs->pg);
759+
void *pgaddr = kmap_local_page(cs->pg);
760760
void *buf = pgaddr + cs->offset;
761761

762762
if (cs->write)
763763
memcpy(buf, *val, ncpy);
764764
else
765765
memcpy(*val, buf, ncpy);
766766

767-
kunmap_atomic(pgaddr);
767+
kunmap_local(pgaddr);
768768
*val += ncpy;
769769
}
770770
*size -= ncpy;
@@ -847,6 +847,12 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
847847

848848
replace_page_cache_page(oldpage, newpage);
849849

850+
/*
851+
* Release while we have extra ref on stolen page. Otherwise
852+
* anon_pipe_buf_release() might think the page can be reused.
853+
*/
854+
pipe_buf_release(cs->pipe, buf);
855+
850856
get_page(newpage);
851857

852858
if (!(buf->flags & PIPE_BUF_FLAG_LRU))
@@ -949,10 +955,10 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
949955
}
950956
}
951957
if (page) {
952-
void *mapaddr = kmap_atomic(page);
958+
void *mapaddr = kmap_local_page(page);
953959
void *buf = mapaddr + offset;
954960
offset += fuse_copy_do(cs, &buf, &count);
955-
kunmap_atomic(mapaddr);
961+
kunmap_local(mapaddr);
956962
} else
957963
offset += fuse_copy_do(cs, NULL, &count);
958964
}
@@ -1591,7 +1597,7 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
15911597
end = outarg.offset + outarg.size;
15921598
if (end > file_size) {
15931599
file_size = end;
1594-
fuse_write_update_size(inode, file_size);
1600+
fuse_write_update_attr(inode, file_size, outarg.size);
15951601
}
15961602

15971603
num = outarg.size;
@@ -2031,8 +2037,12 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
20312037

20322038
pipe_lock(pipe);
20332039
out_free:
2034-
for (idx = 0; idx < nbuf; idx++)
2035-
pipe_buf_release(pipe, &bufs[idx]);
2040+
for (idx = 0; idx < nbuf; idx++) {
2041+
struct pipe_buffer *buf = &bufs[idx];
2042+
2043+
if (buf->ops)
2044+
pipe_buf_release(pipe, buf);
2045+
}
20362046
pipe_unlock(pipe);
20372047

20382048
kvfree(bufs);

fs/fuse/dir.c

Lines changed: 60 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ u64 entry_attr_timeout(struct fuse_entry_out *o)
116116
return time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
117117
}
118118

119-
static void fuse_invalidate_attr_mask(struct inode *inode, u32 mask)
119+
void fuse_invalidate_attr_mask(struct inode *inode, u32 mask)
120120
{
121121
set_mask_bits(&get_fuse_inode(inode)->inval_mask, 0, mask);
122122
}
@@ -738,14 +738,51 @@ static int fuse_symlink(struct user_namespace *mnt_userns, struct inode *dir,
738738
return create_new_entry(fm, &args, dir, entry, S_IFLNK);
739739
}
740740

741-
void fuse_update_ctime(struct inode *inode)
741+
void fuse_flush_time_update(struct inode *inode)
742+
{
743+
int err = sync_inode_metadata(inode, 1);
744+
745+
mapping_set_error(inode->i_mapping, err);
746+
}
747+
748+
static void fuse_update_ctime_in_cache(struct inode *inode)
742749
{
743750
if (!IS_NOCMTIME(inode)) {
744751
inode->i_ctime = current_time(inode);
745752
mark_inode_dirty_sync(inode);
753+
fuse_flush_time_update(inode);
746754
}
747755
}
748756

757+
void fuse_update_ctime(struct inode *inode)
758+
{
759+
fuse_invalidate_attr_mask(inode, STATX_CTIME);
760+
fuse_update_ctime_in_cache(inode);
761+
}
762+
763+
static void fuse_entry_unlinked(struct dentry *entry)
764+
{
765+
struct inode *inode = d_inode(entry);
766+
struct fuse_conn *fc = get_fuse_conn(inode);
767+
struct fuse_inode *fi = get_fuse_inode(inode);
768+
769+
spin_lock(&fi->lock);
770+
fi->attr_version = atomic64_inc_return(&fc->attr_version);
771+
/*
772+
* If i_nlink == 0 then unlink doesn't make sense, yet this can
773+
* happen if userspace filesystem is careless. It would be
774+
* difficult to enforce correct nlink usage so just ignore this
775+
* condition here
776+
*/
777+
if (S_ISDIR(inode->i_mode))
778+
clear_nlink(inode);
779+
else if (inode->i_nlink > 0)
780+
drop_nlink(inode);
781+
spin_unlock(&fi->lock);
782+
fuse_invalidate_entry_cache(entry);
783+
fuse_update_ctime(inode);
784+
}
785+
749786
static int fuse_unlink(struct inode *dir, struct dentry *entry)
750787
{
751788
int err;
@@ -762,24 +799,8 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
762799
args.in_args[0].value = entry->d_name.name;
763800
err = fuse_simple_request(fm, &args);
764801
if (!err) {
765-
struct inode *inode = d_inode(entry);
766-
struct fuse_inode *fi = get_fuse_inode(inode);
767-
768-
spin_lock(&fi->lock);
769-
fi->attr_version = atomic64_inc_return(&fm->fc->attr_version);
770-
/*
771-
* If i_nlink == 0 then unlink doesn't make sense, yet this can
772-
* happen if userspace filesystem is careless. It would be
773-
* difficult to enforce correct nlink usage so just ignore this
774-
* condition here
775-
*/
776-
if (inode->i_nlink > 0)
777-
drop_nlink(inode);
778-
spin_unlock(&fi->lock);
779-
fuse_invalidate_attr(inode);
780802
fuse_dir_changed(dir);
781-
fuse_invalidate_entry_cache(entry);
782-
fuse_update_ctime(inode);
803+
fuse_entry_unlinked(entry);
783804
} else if (err == -EINTR)
784805
fuse_invalidate_entry(entry);
785806
return err;
@@ -801,9 +822,8 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
801822
args.in_args[0].value = entry->d_name.name;
802823
err = fuse_simple_request(fm, &args);
803824
if (!err) {
804-
clear_nlink(d_inode(entry));
805825
fuse_dir_changed(dir);
806-
fuse_invalidate_entry_cache(entry);
826+
fuse_entry_unlinked(entry);
807827
} else if (err == -EINTR)
808828
fuse_invalidate_entry(entry);
809829
return err;
@@ -833,24 +853,18 @@ static int fuse_rename_common(struct inode *olddir, struct dentry *oldent,
833853
err = fuse_simple_request(fm, &args);
834854
if (!err) {
835855
/* ctime changes */
836-
fuse_invalidate_attr(d_inode(oldent));
837856
fuse_update_ctime(d_inode(oldent));
838857

839-
if (flags & RENAME_EXCHANGE) {
840-
fuse_invalidate_attr(d_inode(newent));
858+
if (flags & RENAME_EXCHANGE)
841859
fuse_update_ctime(d_inode(newent));
842-
}
843860

844861
fuse_dir_changed(olddir);
845862
if (olddir != newdir)
846863
fuse_dir_changed(newdir);
847864

848865
/* newent will end up negative */
849-
if (!(flags & RENAME_EXCHANGE) && d_really_is_positive(newent)) {
850-
fuse_invalidate_attr(d_inode(newent));
851-
fuse_invalidate_entry_cache(newent);
852-
fuse_update_ctime(d_inode(newent));
853-
}
866+
if (!(flags & RENAME_EXCHANGE) && d_really_is_positive(newent))
867+
fuse_entry_unlinked(newent);
854868
} else if (err == -EINTR) {
855869
/* If request was interrupted, DEITY only knows if the
856870
rename actually took place. If the invalidation
@@ -916,25 +930,11 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
916930
args.in_args[1].size = newent->d_name.len + 1;
917931
args.in_args[1].value = newent->d_name.name;
918932
err = create_new_entry(fm, &args, newdir, newent, inode->i_mode);
919-
/* Contrary to "normal" filesystems it can happen that link
920-
makes two "logical" inodes point to the same "physical"
921-
inode. We invalidate the attributes of the old one, so it
922-
will reflect changes in the backing inode (link count,
923-
etc.)
924-
*/
925-
if (!err) {
926-
struct fuse_inode *fi = get_fuse_inode(inode);
927-
928-
spin_lock(&fi->lock);
929-
fi->attr_version = atomic64_inc_return(&fm->fc->attr_version);
930-
if (likely(inode->i_nlink < UINT_MAX))
931-
inc_nlink(inode);
932-
spin_unlock(&fi->lock);
933-
fuse_invalidate_attr(inode);
934-
fuse_update_ctime(inode);
935-
} else if (err == -EINTR) {
933+
if (!err)
934+
fuse_update_ctime_in_cache(inode);
935+
else if (err == -EINTR)
936936
fuse_invalidate_attr(inode);
937-
}
937+
938938
return err;
939939
}
940940

@@ -944,15 +944,6 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
944944
unsigned int blkbits;
945945
struct fuse_conn *fc = get_fuse_conn(inode);
946946

947-
/* see the comment in fuse_change_attributes() */
948-
if (fc->writeback_cache && S_ISREG(inode->i_mode)) {
949-
attr->size = i_size_read(inode);
950-
attr->mtime = inode->i_mtime.tv_sec;
951-
attr->mtimensec = inode->i_mtime.tv_nsec;
952-
attr->ctime = inode->i_ctime.tv_sec;
953-
attr->ctimensec = inode->i_ctime.tv_nsec;
954-
}
955-
956947
stat->dev = inode->i_sb->s_dev;
957948
stat->ino = attr->ino;
958949
stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
@@ -1030,12 +1021,14 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
10301021
struct fuse_inode *fi = get_fuse_inode(inode);
10311022
int err = 0;
10321023
bool sync;
1024+
u32 inval_mask = READ_ONCE(fi->inval_mask);
1025+
u32 cache_mask = fuse_get_cache_mask(inode);
10331026

10341027
if (flags & AT_STATX_FORCE_SYNC)
10351028
sync = true;
10361029
else if (flags & AT_STATX_DONT_SYNC)
10371030
sync = false;
1038-
else if (request_mask & READ_ONCE(fi->inval_mask))
1031+
else if (request_mask & inval_mask & ~cache_mask)
10391032
sync = true;
10401033
else
10411034
sync = time_before64(fi->i_time, get_jiffies_64());
@@ -1052,11 +1045,9 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
10521045
return err;
10531046
}
10541047

1055-
int fuse_update_attributes(struct inode *inode, struct file *file)
1048+
int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask)
10561049
{
1057-
/* Do *not* need to get atime for internal purposes */
1058-
return fuse_update_get_attr(inode, file, NULL,
1059-
STATX_BASIC_STATS & ~STATX_ATIME, 0);
1050+
return fuse_update_get_attr(inode, file, NULL, mask, 0);
10601051
}
10611052

10621053
int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
@@ -1071,7 +1062,7 @@ int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
10711062
if (!parent)
10721063
return -ENOENT;
10731064

1074-
inode_lock(parent);
1065+
inode_lock_nested(parent, I_MUTEX_PARENT);
10751066
if (!S_ISDIR(parent->i_mode))
10761067
goto unlock;
10771068

@@ -1561,10 +1552,10 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
15611552
struct fuse_setattr_in inarg;
15621553
struct fuse_attr_out outarg;
15631554
bool is_truncate = false;
1564-
bool is_wb = fc->writeback_cache;
1555+
bool is_wb = fc->writeback_cache && S_ISREG(inode->i_mode);
15651556
loff_t oldsize;
15661557
int err;
1567-
bool trust_local_cmtime = is_wb && S_ISREG(inode->i_mode);
1558+
bool trust_local_cmtime = is_wb;
15681559
bool fault_blocked = false;
15691560

15701561
if (!fc->default_permissions)
@@ -1608,7 +1599,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
16081599
}
16091600

16101601
/* Flush dirty data/metadata before non-truncate SETATTR */
1611-
if (is_wb && S_ISREG(inode->i_mode) &&
1602+
if (is_wb &&
16121603
attr->ia_valid &
16131604
(ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_MTIME_SET |
16141605
ATTR_TIMES_SET)) {
@@ -1676,10 +1667,11 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
16761667
}
16771668

16781669
fuse_change_attributes_common(inode, &outarg.attr,
1679-
attr_timeout(&outarg));
1670+
attr_timeout(&outarg),
1671+
fuse_get_cache_mask(inode));
16801672
oldsize = inode->i_size;
16811673
/* see the comment in fuse_change_attributes() */
1682-
if (!is_wb || is_truncate || !S_ISREG(inode->i_mode))
1674+
if (!is_wb || is_truncate)
16831675
i_size_write(inode, outarg.attr.size);
16841676

16851677
if (is_truncate) {

0 commit comments

Comments
 (0)