diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-16 14:46:31 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-16 14:46:31 -0400 |
| commit | 2eac9eb8a2e64cbfcc300e9a8098edf424c1d16c (patch) | |
| tree | f3c4b8f25e2d25915e14ced10db661cae1341807 | |
| parent | ad54e461137765aaf090eb7f54c3b51fc0ad5d62 (diff) | |
| parent | fb6ccff667712c46b4501b920ea73a326e49626a (diff) | |
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: verify all ioctl retry iov elements
fuse: add missing INIT flag descriptions
fuse: add missing INIT flags
fuse: update attributes on aio_read
fuse: invalidate inode mapping if mtime changes
fuse: add FUSE_AUTO_INVAL_DATA init flag
| -rw-r--r-- | fs/fuse/file.c | 15 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 3 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 32 | ||||
| -rw-r--r-- | include/linux/fuse.h | 19 |
4 files changed, 58 insertions, 11 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 93d8d6c9494d..aba15f1b7ad2 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
| @@ -703,13 +703,16 @@ static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
| 703 | unsigned long nr_segs, loff_t pos) | 703 | unsigned long nr_segs, loff_t pos) |
| 704 | { | 704 | { |
| 705 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 705 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
| 706 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
| 706 | 707 | ||
| 707 | if (pos + iov_length(iov, nr_segs) > i_size_read(inode)) { | 708 | /* |
| 709 | * In auto invalidate mode, always update attributes on read. | ||
| 710 | * Otherwise, only update if we attempt to read past EOF (to ensure | ||
| 711 | * i_size is up to date). | ||
| 712 | */ | ||
| 713 | if (fc->auto_inval_data || | ||
| 714 | (pos + iov_length(iov, nr_segs) > i_size_read(inode))) { | ||
| 708 | int err; | 715 | int err; |
| 709 | /* | ||
| 710 | * If trying to read past EOF, make sure the i_size | ||
| 711 | * attribute is up-to-date. | ||
| 712 | */ | ||
| 713 | err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL); | 716 | err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL); |
| 714 | if (err) | 717 | if (err) |
| 715 | return err; | 718 | return err; |
| @@ -1700,7 +1703,7 @@ static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count) | |||
| 1700 | size_t n; | 1703 | size_t n; |
| 1701 | u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT; | 1704 | u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT; |
| 1702 | 1705 | ||
| 1703 | for (n = 0; n < count; n++) { | 1706 | for (n = 0; n < count; n++, iov++) { |
| 1704 | if (iov->iov_len > (size_t) max) | 1707 | if (iov->iov_len > (size_t) max) |
| 1705 | return -ENOMEM; | 1708 | return -ENOMEM; |
| 1706 | max -= iov->iov_len; | 1709 | max -= iov->iov_len; |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 771fb6322c07..e24dd74e3068 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
| @@ -484,6 +484,9 @@ struct fuse_conn { | |||
| 484 | /** Is fallocate not implemented by fs? */ | 484 | /** Is fallocate not implemented by fs? */ |
| 485 | unsigned no_fallocate:1; | 485 | unsigned no_fallocate:1; |
| 486 | 486 | ||
| 487 | /** Use enhanced/automatic page cache invalidation. */ | ||
| 488 | unsigned auto_inval_data:1; | ||
| 489 | |||
| 487 | /** The number of requests waiting for completion */ | 490 | /** The number of requests waiting for completion */ |
| 488 | atomic_t num_waiting; | 491 | atomic_t num_waiting; |
| 489 | 492 | ||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 1cd61652018c..ce0a2838ccd0 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -197,6 +197,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | |||
| 197 | struct fuse_conn *fc = get_fuse_conn(inode); | 197 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 198 | struct fuse_inode *fi = get_fuse_inode(inode); | 198 | struct fuse_inode *fi = get_fuse_inode(inode); |
| 199 | loff_t oldsize; | 199 | loff_t oldsize; |
| 200 | struct timespec old_mtime; | ||
| 200 | 201 | ||
| 201 | spin_lock(&fc->lock); | 202 | spin_lock(&fc->lock); |
| 202 | if (attr_version != 0 && fi->attr_version > attr_version) { | 203 | if (attr_version != 0 && fi->attr_version > attr_version) { |
| @@ -204,15 +205,35 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | |||
| 204 | return; | 205 | return; |
| 205 | } | 206 | } |
| 206 | 207 | ||
| 208 | old_mtime = inode->i_mtime; | ||
| 207 | fuse_change_attributes_common(inode, attr, attr_valid); | 209 | fuse_change_attributes_common(inode, attr, attr_valid); |
| 208 | 210 | ||
| 209 | oldsize = inode->i_size; | 211 | oldsize = inode->i_size; |
| 210 | i_size_write(inode, attr->size); | 212 | i_size_write(inode, attr->size); |
| 211 | spin_unlock(&fc->lock); | 213 | spin_unlock(&fc->lock); |
| 212 | 214 | ||
| 213 | if (S_ISREG(inode->i_mode) && oldsize != attr->size) { | 215 | if (S_ISREG(inode->i_mode)) { |
| 214 | truncate_pagecache(inode, oldsize, attr->size); | 216 | bool inval = false; |
| 215 | invalidate_inode_pages2(inode->i_mapping); | 217 | |
| 218 | if (oldsize != attr->size) { | ||
| 219 | truncate_pagecache(inode, oldsize, attr->size); | ||
| 220 | inval = true; | ||
| 221 | } else if (fc->auto_inval_data) { | ||
| 222 | struct timespec new_mtime = { | ||
| 223 | .tv_sec = attr->mtime, | ||
| 224 | .tv_nsec = attr->mtimensec, | ||
| 225 | }; | ||
| 226 | |||
| 227 | /* | ||
| 228 | * Auto inval mode also checks and invalidates if mtime | ||
| 229 | * has changed. | ||
| 230 | */ | ||
| 231 | if (!timespec_equal(&old_mtime, &new_mtime)) | ||
| 232 | inval = true; | ||
| 233 | } | ||
| 234 | |||
| 235 | if (inval) | ||
| 236 | invalidate_inode_pages2(inode->i_mapping); | ||
| 216 | } | 237 | } |
| 217 | } | 238 | } |
| 218 | 239 | ||
| @@ -834,6 +855,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
| 834 | fc->big_writes = 1; | 855 | fc->big_writes = 1; |
| 835 | if (arg->flags & FUSE_DONT_MASK) | 856 | if (arg->flags & FUSE_DONT_MASK) |
| 836 | fc->dont_mask = 1; | 857 | fc->dont_mask = 1; |
| 858 | if (arg->flags & FUSE_AUTO_INVAL_DATA) | ||
| 859 | fc->auto_inval_data = 1; | ||
| 837 | } else { | 860 | } else { |
| 838 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; | 861 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; |
| 839 | fc->no_lock = 1; | 862 | fc->no_lock = 1; |
| @@ -859,7 +882,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
| 859 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; | 882 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; |
| 860 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | | 883 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | |
| 861 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK | | 884 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK | |
| 862 | FUSE_FLOCK_LOCKS; | 885 | FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ | |
| 886 | FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA; | ||
| 863 | req->in.h.opcode = FUSE_INIT; | 887 | req->in.h.opcode = FUSE_INIT; |
| 864 | req->in.numargs = 1; | 888 | req->in.numargs = 1; |
| 865 | req->in.args[0].size = sizeof(*arg); | 889 | req->in.args[0].size = sizeof(*arg); |
diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 9303348965fb..d8c713e148e3 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h | |||
| @@ -57,6 +57,9 @@ | |||
| 57 | * | 57 | * |
| 58 | * 7.19 | 58 | * 7.19 |
| 59 | * - add FUSE_FALLOCATE | 59 | * - add FUSE_FALLOCATE |
| 60 | * | ||
| 61 | * 7.20 | ||
| 62 | * - add FUSE_AUTO_INVAL_DATA | ||
| 60 | */ | 63 | */ |
| 61 | 64 | ||
| 62 | #ifndef _LINUX_FUSE_H | 65 | #ifndef _LINUX_FUSE_H |
| @@ -88,7 +91,7 @@ | |||
| 88 | #define FUSE_KERNEL_VERSION 7 | 91 | #define FUSE_KERNEL_VERSION 7 |
| 89 | 92 | ||
| 90 | /** Minor version number of this interface */ | 93 | /** Minor version number of this interface */ |
| 91 | #define FUSE_KERNEL_MINOR_VERSION 19 | 94 | #define FUSE_KERNEL_MINOR_VERSION 20 |
| 92 | 95 | ||
| 93 | /** The node ID of the root inode */ | 96 | /** The node ID of the root inode */ |
| 94 | #define FUSE_ROOT_ID 1 | 97 | #define FUSE_ROOT_ID 1 |
| @@ -163,10 +166,19 @@ struct fuse_file_lock { | |||
| 163 | /** | 166 | /** |
| 164 | * INIT request/reply flags | 167 | * INIT request/reply flags |
| 165 | * | 168 | * |
| 169 | * FUSE_ASYNC_READ: asynchronous read requests | ||
| 166 | * FUSE_POSIX_LOCKS: remote locking for POSIX file locks | 170 | * FUSE_POSIX_LOCKS: remote locking for POSIX file locks |
| 171 | * FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported) | ||
| 172 | * FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem | ||
| 167 | * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." | 173 | * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." |
| 174 | * FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB | ||
| 168 | * FUSE_DONT_MASK: don't apply umask to file mode on create operations | 175 | * FUSE_DONT_MASK: don't apply umask to file mode on create operations |
| 176 | * FUSE_SPLICE_WRITE: kernel supports splice write on the device | ||
| 177 | * FUSE_SPLICE_MOVE: kernel supports splice move on the device | ||
| 178 | * FUSE_SPLICE_READ: kernel supports splice read on the device | ||
| 169 | * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks | 179 | * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks |
| 180 | * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories | ||
| 181 | * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages | ||
| 170 | */ | 182 | */ |
| 171 | #define FUSE_ASYNC_READ (1 << 0) | 183 | #define FUSE_ASYNC_READ (1 << 0) |
| 172 | #define FUSE_POSIX_LOCKS (1 << 1) | 184 | #define FUSE_POSIX_LOCKS (1 << 1) |
| @@ -175,7 +187,12 @@ struct fuse_file_lock { | |||
| 175 | #define FUSE_EXPORT_SUPPORT (1 << 4) | 187 | #define FUSE_EXPORT_SUPPORT (1 << 4) |
| 176 | #define FUSE_BIG_WRITES (1 << 5) | 188 | #define FUSE_BIG_WRITES (1 << 5) |
| 177 | #define FUSE_DONT_MASK (1 << 6) | 189 | #define FUSE_DONT_MASK (1 << 6) |
| 190 | #define FUSE_SPLICE_WRITE (1 << 7) | ||
| 191 | #define FUSE_SPLICE_MOVE (1 << 8) | ||
| 192 | #define FUSE_SPLICE_READ (1 << 9) | ||
| 178 | #define FUSE_FLOCK_LOCKS (1 << 10) | 193 | #define FUSE_FLOCK_LOCKS (1 << 10) |
| 194 | #define FUSE_HAS_IOCTL_DIR (1 << 11) | ||
| 195 | #define FUSE_AUTO_INVAL_DATA (1 << 12) | ||
| 179 | 196 | ||
| 180 | /** | 197 | /** |
| 181 | * CUSE INIT request/reply flags | 198 | * CUSE INIT request/reply flags |
