Skip to content

Commit dbfad21

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse updates from Miklos Szeredi. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: fuse: use flexible array in fuse.h fuse: allow nanosecond granularity fuse: O_DIRECT support for files fuse: fix nlink after unlink
2 parents 743e89e + c628ee6 commit dbfad21

File tree

4 files changed

+129
-28
lines changed

4 files changed

+129
-28
lines changed

fs/fuse/dir.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -387,9 +387,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
387387
if (fc->no_create)
388388
return -ENOSYS;
389389

390-
if (flags & O_DIRECT)
391-
return -EINVAL;
392-
393390
forget = fuse_alloc_forget();
394391
if (!forget)
395392
return -ENOMEM;
@@ -644,13 +641,12 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
644641
fuse_put_request(fc, req);
645642
if (!err) {
646643
struct inode *inode = entry->d_inode;
644+
struct fuse_inode *fi = get_fuse_inode(inode);
647645

648-
/*
649-
* Set nlink to zero so the inode can be cleared, if the inode
650-
* does have more links this will be discovered at the next
651-
* lookup/getattr.
652-
*/
653-
clear_nlink(inode);
646+
spin_lock(&fc->lock);
647+
fi->attr_version = ++fc->attr_version;
648+
drop_nlink(inode);
649+
spin_unlock(&fc->lock);
654650
fuse_invalidate_attr(inode);
655651
fuse_invalidate_attr(dir);
656652
fuse_invalidate_entry_cache(entry);
@@ -762,8 +758,17 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
762758
will reflect changes in the backing inode (link count,
763759
etc.)
764760
*/
765-
if (!err || err == -EINTR)
761+
if (!err) {
762+
struct fuse_inode *fi = get_fuse_inode(inode);
763+
764+
spin_lock(&fc->lock);
765+
fi->attr_version = ++fc->attr_version;
766+
inc_nlink(inode);
767+
spin_unlock(&fc->lock);
768+
fuse_invalidate_attr(inode);
769+
} else if (err == -EINTR) {
766770
fuse_invalidate_attr(inode);
771+
}
767772
return err;
768773
}
769774

fs/fuse/file.c

Lines changed: 112 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,6 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
194194
struct fuse_conn *fc = get_fuse_conn(inode);
195195
int err;
196196

197-
/* VFS checks this, but only _after_ ->open() */
198-
if (file->f_flags & O_DIRECT)
199-
return -EINVAL;
200-
201197
err = generic_file_open(inode, file);
202198
if (err)
203199
return err;
@@ -932,17 +928,23 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
932928
struct file *file = iocb->ki_filp;
933929
struct address_space *mapping = file->f_mapping;
934930
size_t count = 0;
931+
size_t ocount = 0;
935932
ssize_t written = 0;
933+
ssize_t written_buffered = 0;
936934
struct inode *inode = mapping->host;
937935
ssize_t err;
938936
struct iov_iter i;
937+
loff_t endbyte = 0;
939938

940939
WARN_ON(iocb->ki_pos != pos);
941940

942-
err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
941+
ocount = 0;
942+
err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
943943
if (err)
944944
return err;
945945

946+
count = ocount;
947+
946948
mutex_lock(&inode->i_mutex);
947949
vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
948950

@@ -962,11 +964,41 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
962964

963965
file_update_time(file);
964966

965-
iov_iter_init(&i, iov, nr_segs, count, 0);
966-
written = fuse_perform_write(file, mapping, &i, pos);
967-
if (written >= 0)
968-
iocb->ki_pos = pos + written;
967+
if (file->f_flags & O_DIRECT) {
968+
written = generic_file_direct_write(iocb, iov, &nr_segs,
969+
pos, &iocb->ki_pos,
970+
count, ocount);
971+
if (written < 0 || written == count)
972+
goto out;
973+
974+
pos += written;
975+
count -= written;
969976

977+
iov_iter_init(&i, iov, nr_segs, count, written);
978+
written_buffered = fuse_perform_write(file, mapping, &i, pos);
979+
if (written_buffered < 0) {
980+
err = written_buffered;
981+
goto out;
982+
}
983+
endbyte = pos + written_buffered - 1;
984+
985+
err = filemap_write_and_wait_range(file->f_mapping, pos,
986+
endbyte);
987+
if (err)
988+
goto out;
989+
990+
invalidate_mapping_pages(file->f_mapping,
991+
pos >> PAGE_CACHE_SHIFT,
992+
endbyte >> PAGE_CACHE_SHIFT);
993+
994+
written += written_buffered;
995+
iocb->ki_pos = pos + written_buffered;
996+
} else {
997+
iov_iter_init(&i, iov, nr_segs, count, 0);
998+
written = fuse_perform_write(file, mapping, &i, pos);
999+
if (written >= 0)
1000+
iocb->ki_pos = pos + written;
1001+
}
9701002
out:
9711003
current->backing_dev_info = NULL;
9721004
mutex_unlock(&inode->i_mutex);
@@ -1101,30 +1133,41 @@ static ssize_t fuse_direct_read(struct file *file, char __user *buf,
11011133
return res;
11021134
}
11031135

1104-
static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
1105-
size_t count, loff_t *ppos)
1136+
static ssize_t __fuse_direct_write(struct file *file, const char __user *buf,
1137+
size_t count, loff_t *ppos)
11061138
{
11071139
struct inode *inode = file->f_path.dentry->d_inode;
11081140
ssize_t res;
11091141

1110-
if (is_bad_inode(inode))
1111-
return -EIO;
1112-
1113-
/* Don't allow parallel writes to the same file */
1114-
mutex_lock(&inode->i_mutex);
11151142
res = generic_write_checks(file, ppos, &count, 0);
11161143
if (!res) {
11171144
res = fuse_direct_io(file, buf, count, ppos, 1);
11181145
if (res > 0)
11191146
fuse_write_update_size(inode, *ppos);
11201147
}
1121-
mutex_unlock(&inode->i_mutex);
11221148

11231149
fuse_invalidate_attr(inode);
11241150

11251151
return res;
11261152
}
11271153

1154+
static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
1155+
size_t count, loff_t *ppos)
1156+
{
1157+
struct inode *inode = file->f_path.dentry->d_inode;
1158+
ssize_t res;
1159+
1160+
if (is_bad_inode(inode))
1161+
return -EIO;
1162+
1163+
/* Don't allow parallel writes to the same file */
1164+
mutex_lock(&inode->i_mutex);
1165+
res = __fuse_direct_write(file, buf, count, ppos);
1166+
mutex_unlock(&inode->i_mutex);
1167+
1168+
return res;
1169+
}
1170+
11281171
static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req)
11291172
{
11301173
__free_page(req->pages[0]);
@@ -2077,6 +2120,57 @@ int fuse_notify_poll_wakeup(struct fuse_conn *fc,
20772120
return 0;
20782121
}
20792122

2123+
static ssize_t fuse_loop_dio(struct file *filp, const struct iovec *iov,
2124+
unsigned long nr_segs, loff_t *ppos, int rw)
2125+
{
2126+
const struct iovec *vector = iov;
2127+
ssize_t ret = 0;
2128+
2129+
while (nr_segs > 0) {
2130+
void __user *base;
2131+
size_t len;
2132+
ssize_t nr;
2133+
2134+
base = vector->iov_base;
2135+
len = vector->iov_len;
2136+
vector++;
2137+
nr_segs--;
2138+
2139+
if (rw == WRITE)
2140+
nr = __fuse_direct_write(filp, base, len, ppos);
2141+
else
2142+
nr = fuse_direct_read(filp, base, len, ppos);
2143+
2144+
if (nr < 0) {
2145+
if (!ret)
2146+
ret = nr;
2147+
break;
2148+
}
2149+
ret += nr;
2150+
if (nr != len)
2151+
break;
2152+
}
2153+
2154+
return ret;
2155+
}
2156+
2157+
2158+
static ssize_t
2159+
fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
2160+
loff_t offset, unsigned long nr_segs)
2161+
{
2162+
ssize_t ret = 0;
2163+
struct file *file = NULL;
2164+
loff_t pos = 0;
2165+
2166+
file = iocb->ki_filp;
2167+
pos = offset;
2168+
2169+
ret = fuse_loop_dio(file, iov, nr_segs, &pos, rw);
2170+
2171+
return ret;
2172+
}
2173+
20802174
static const struct file_operations fuse_file_operations = {
20812175
.llseek = fuse_file_llseek,
20822176
.read = do_sync_read,
@@ -2120,6 +2214,7 @@ static const struct address_space_operations fuse_file_aops = {
21202214
.readpages = fuse_readpages,
21212215
.set_page_dirty = __set_page_dirty_nobuffers,
21222216
.bmap = fuse_bmap,
2217+
.direct_IO = fuse_direct_IO,
21232218
};
21242219

21252220
void fuse_init_file_inode(struct inode *inode)

fs/fuse/inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
947947
sb->s_magic = FUSE_SUPER_MAGIC;
948948
sb->s_op = &fuse_super_operations;
949949
sb->s_maxbytes = MAX_LFS_FILESIZE;
950+
sb->s_time_gran = 1;
950951
sb->s_export_op = &fuse_export_operations;
951952

952953
file = fget(d.fd);

include/linux/fuse.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ struct fuse_dirent {
593593
__u64 off;
594594
__u32 namelen;
595595
__u32 type;
596-
char name[0];
596+
char name[];
597597
};
598598

599599
#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)

0 commit comments

Comments
 (0)