aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2007-11-28 19:21:59 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-29 12:24:54 -0500
commitbcb4be809d2a804ff040d95db4a664113833e702 (patch)
tree11a3aad0dc7df29906e2b379d13f14ccf26c9b56
parentb6fd6ecb830444636bc4e9d626f214082c91fffe (diff)
fuse: fix reading past EOF
Currently reading a fuse file will stop at cached i_size and return EOF, even though the file might have grown since the attributes were last updated. So detect if trying to read past EOF, and refresh the attributes before continuing with the read. Thanks to mpb for the report. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/fuse/dir.c48
-rw-r--r--fs/fuse/file.c21
-rw-r--r--fs/fuse/fuse_i.h3
3 files changed, 52 insertions, 20 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 3763757f9fe7..7b3df35cf196 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -775,6 +775,31 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
775 return err; 775 return err;
776} 776}
777 777
778int fuse_update_attributes(struct inode *inode, struct kstat *stat,
779 struct file *file, bool *refreshed)
780{
781 struct fuse_inode *fi = get_fuse_inode(inode);
782 int err;
783 bool r;
784
785 if (fi->i_time < get_jiffies_64()) {
786 r = true;
787 err = fuse_do_getattr(inode, stat, file);
788 } else {
789 r = false;
790 err = 0;
791 if (stat) {
792 generic_fillattr(inode, stat);
793 stat->mode = fi->orig_i_mode;
794 }
795 }
796
797 if (refreshed != NULL)
798 *refreshed = r;
799
800 return err;
801}
802
778/* 803/*
779 * Calling into a user-controlled filesystem gives the filesystem 804 * Calling into a user-controlled filesystem gives the filesystem
780 * daemon ptrace-like capabilities over the requester process. This 805 * daemon ptrace-like capabilities over the requester process. This
@@ -862,14 +887,9 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
862 */ 887 */
863 if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || 888 if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) ||
864 ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { 889 ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) {
865 struct fuse_inode *fi = get_fuse_inode(inode); 890 err = fuse_update_attributes(inode, NULL, NULL, &refreshed);
866 if (fi->i_time < get_jiffies_64()) { 891 if (err)
867 err = fuse_do_getattr(inode, NULL, NULL); 892 return err;
868 if (err)
869 return err;
870
871 refreshed = true;
872 }
873 } 893 }
874 894
875 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 895 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
@@ -1173,22 +1193,12 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
1173 struct kstat *stat) 1193 struct kstat *stat)
1174{ 1194{
1175 struct inode *inode = entry->d_inode; 1195 struct inode *inode = entry->d_inode;
1176 struct fuse_inode *fi = get_fuse_inode(inode);
1177 struct fuse_conn *fc = get_fuse_conn(inode); 1196 struct fuse_conn *fc = get_fuse_conn(inode);
1178 int err;
1179 1197
1180 if (!fuse_allow_task(fc, current)) 1198 if (!fuse_allow_task(fc, current))
1181 return -EACCES; 1199 return -EACCES;
1182 1200
1183 if (fi->i_time < get_jiffies_64()) 1201 return fuse_update_attributes(inode, stat, NULL, NULL);
1184 err = fuse_do_getattr(inode, stat, NULL);
1185 else {
1186 err = 0;
1187 generic_fillattr(inode, stat);
1188 stat->mode = fi->orig_i_mode;
1189 }
1190
1191 return err;
1192} 1202}
1193 1203
1194static int fuse_setxattr(struct dentry *entry, const char *name, 1204static int fuse_setxattr(struct dentry *entry, const char *name,
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 535b37399009..474968fbb555 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -453,6 +453,25 @@ out:
453 return err; 453 return err;
454} 454}
455 455
456static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
457 unsigned long nr_segs, loff_t pos)
458{
459 struct inode *inode = iocb->ki_filp->f_mapping->host;
460
461 if (pos + iov_length(iov, nr_segs) > i_size_read(inode)) {
462 int err;
463 /*
464 * If trying to read past EOF, make sure the i_size
465 * attribute is up-to-date.
466 */
467 err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL);
468 if (err)
469 return err;
470 }
471
472 return generic_file_aio_read(iocb, iov, nr_segs, pos);
473}
474
456static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, 475static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
457 struct inode *inode, loff_t pos, size_t count, 476 struct inode *inode, loff_t pos, size_t count,
458 int writepage) 477 int writepage)
@@ -887,7 +906,7 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
887static const struct file_operations fuse_file_operations = { 906static const struct file_operations fuse_file_operations = {
888 .llseek = generic_file_llseek, 907 .llseek = generic_file_llseek,
889 .read = do_sync_read, 908 .read = do_sync_read,
890 .aio_read = generic_file_aio_read, 909 .aio_read = fuse_file_aio_read,
891 .write = do_sync_write, 910 .write = do_sync_write,
892 .aio_write = generic_file_aio_write, 911 .aio_write = generic_file_aio_write,
893 .mmap = fuse_file_mmap, 912 .mmap = fuse_file_mmap,
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 6c5461de1a5f..19b0129c9811 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -593,3 +593,6 @@ int fuse_valid_type(int m);
593int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task); 593int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task);
594 594
595u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id); 595u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id);
596
597int fuse_update_attributes(struct inode *inode, struct kstat *stat,
598 struct file *file, bool *refreshed);