aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Muir <muirj@nortel.com>2009-05-31 11:13:57 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2009-06-30 14:12:24 -0400
commit3b463ae0c6264f70e5d4c0a9c46af20fed43c96e (patch)
tree03c6abdd0671d74452cbd1f6fc6d637363eb6389
parente0a43ddcc08c34dbd666d93600fd23914505f4aa (diff)
fuse: invalidation reverse calls
Add notification messages that allow the filesystem to invalidate VFS caches. Two notifications are added: 1) inode invalidation - invalidate cached attributes - invalidate a range of pages in the page cache (this is optional) 2) dentry invalidation - try to invalidate a subtree in the dentry cache Care must be taken while accessing the 'struct super_block' for the mount, as it can go away while an invalidation is in progress. To prevent this, introduce a rw-semaphore, that is taken for read during the invalidation and taken for write in the ->kill_sb callback. Cc: Csaba Henk <csaba@gluster.com> Cc: Anand Avati <avati@zresearch.com> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
-rw-r--r--fs/fuse/dev.c81
-rw-r--r--fs/fuse/dir.c37
-rw-r--r--fs/fuse/fuse_i.h24
-rw-r--r--fs/fuse/inode.c59
-rw-r--r--include/linux/fuse.h16
5 files changed, 214 insertions, 3 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 8a11a8c67c42..f58ecbc416c8 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -849,6 +849,81 @@ err:
849 return err; 849 return err;
850} 850}
851 851
852static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size,
853 struct fuse_copy_state *cs)
854{
855 struct fuse_notify_inval_inode_out outarg;
856 int err = -EINVAL;
857
858 if (size != sizeof(outarg))
859 goto err;
860
861 err = fuse_copy_one(cs, &outarg, sizeof(outarg));
862 if (err)
863 goto err;
864 fuse_copy_finish(cs);
865
866 down_read(&fc->killsb);
867 err = -ENOENT;
868 if (!fc->sb)
869 goto err_unlock;
870
871 err = fuse_reverse_inval_inode(fc->sb, outarg.ino,
872 outarg.off, outarg.len);
873
874err_unlock:
875 up_read(&fc->killsb);
876 return err;
877
878err:
879 fuse_copy_finish(cs);
880 return err;
881}
882
883static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
884 struct fuse_copy_state *cs)
885{
886 struct fuse_notify_inval_entry_out outarg;
887 int err = -EINVAL;
888 char buf[FUSE_NAME_MAX+1];
889 struct qstr name;
890
891 if (size < sizeof(outarg))
892 goto err;
893
894 err = fuse_copy_one(cs, &outarg, sizeof(outarg));
895 if (err)
896 goto err;
897
898 err = -ENAMETOOLONG;
899 if (outarg.namelen > FUSE_NAME_MAX)
900 goto err;
901
902 name.name = buf;
903 name.len = outarg.namelen;
904 err = fuse_copy_one(cs, buf, outarg.namelen + 1);
905 if (err)
906 goto err;
907 fuse_copy_finish(cs);
908 buf[outarg.namelen] = 0;
909 name.hash = full_name_hash(name.name, name.len);
910
911 down_read(&fc->killsb);
912 err = -ENOENT;
913 if (!fc->sb)
914 goto err_unlock;
915
916 err = fuse_reverse_inval_entry(fc->sb, outarg.parent, &name);
917
918err_unlock:
919 up_read(&fc->killsb);
920 return err;
921
922err:
923 fuse_copy_finish(cs);
924 return err;
925}
926
852static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, 927static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
853 unsigned int size, struct fuse_copy_state *cs) 928 unsigned int size, struct fuse_copy_state *cs)
854{ 929{
@@ -856,6 +931,12 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
856 case FUSE_NOTIFY_POLL: 931 case FUSE_NOTIFY_POLL:
857 return fuse_notify_poll(fc, size, cs); 932 return fuse_notify_poll(fc, size, cs);
858 933
934 case FUSE_NOTIFY_INVAL_INODE:
935 return fuse_notify_inval_inode(fc, size, cs);
936
937 case FUSE_NOTIFY_INVAL_ENTRY:
938 return fuse_notify_inval_entry(fc, size, cs);
939
859 default: 940 default:
860 fuse_copy_finish(cs); 941 fuse_copy_finish(cs);
861 return -EINVAL; 942 return -EINVAL;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 6b700734e519..e703654e7f40 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -859,6 +859,43 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat,
859 return err; 859 return err;
860} 860}
861 861
862int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
863 struct qstr *name)
864{
865 int err = -ENOTDIR;
866 struct inode *parent;
867 struct dentry *dir;
868 struct dentry *entry;
869
870 parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid);
871 if (!parent)
872 return -ENOENT;
873
874 mutex_lock(&parent->i_mutex);
875 if (!S_ISDIR(parent->i_mode))
876 goto unlock;
877
878 err = -ENOENT;
879 dir = d_find_alias(parent);
880 if (!dir)
881 goto unlock;
882
883 entry = d_lookup(dir, name);
884 dput(dir);
885 if (!entry)
886 goto unlock;
887
888 fuse_invalidate_attr(parent);
889 fuse_invalidate_entry(entry);
890 dput(entry);
891 err = 0;
892
893 unlock:
894 mutex_unlock(&parent->i_mutex);
895 iput(parent);
896 return err;
897}
898
862/* 899/*
863 * Calling into a user-controlled filesystem gives the filesystem 900 * Calling into a user-controlled filesystem gives the filesystem
864 * daemon ptrace-like capabilities over the requester process. This 901 * daemon ptrace-like capabilities over the requester process. This
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index ede4f77b2d6c..52b641fc0faf 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -484,6 +484,12 @@ struct fuse_conn {
484 484
485 /** Called on final put */ 485 /** Called on final put */
486 void (*release)(struct fuse_conn *); 486 void (*release)(struct fuse_conn *);
487
488 /** Super block for this connection. */
489 struct super_block *sb;
490
491 /** Read/write semaphore to hold when accessing sb. */
492 struct rw_semaphore killsb;
487}; 493};
488 494
489static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) 495static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
@@ -512,6 +518,11 @@ extern const struct file_operations fuse_dev_operations;
512extern const struct dentry_operations fuse_dentry_operations; 518extern const struct dentry_operations fuse_dentry_operations;
513 519
514/** 520/**
521 * Inode to nodeid comparison.
522 */
523int fuse_inode_eq(struct inode *inode, void *_nodeidp);
524
525/**
515 * Get a filled in inode 526 * Get a filled in inode
516 */ 527 */
517struct inode *fuse_iget(struct super_block *sb, u64 nodeid, 528struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
@@ -711,6 +722,19 @@ void fuse_release_nowrite(struct inode *inode);
711 722
712u64 fuse_get_attr_version(struct fuse_conn *fc); 723u64 fuse_get_attr_version(struct fuse_conn *fc);
713 724
725/**
726 * File-system tells the kernel to invalidate cache for the given node id.
727 */
728int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
729 loff_t offset, loff_t len);
730
731/**
732 * File-system tells the kernel to invalidate parent attributes and
733 * the dentry matching parent/name.
734 */
735int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
736 struct qstr *name);
737
714int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, 738int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
715 bool isdir); 739 bool isdir);
716ssize_t fuse_direct_io(struct file *file, const char __user *buf, 740ssize_t fuse_direct_io(struct file *file, const char __user *buf,
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 6cc501bd0187..f91ccc4a189d 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -206,7 +206,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
206 BUG(); 206 BUG();
207} 207}
208 208
209static int fuse_inode_eq(struct inode *inode, void *_nodeidp) 209int fuse_inode_eq(struct inode *inode, void *_nodeidp)
210{ 210{
211 u64 nodeid = *(u64 *) _nodeidp; 211 u64 nodeid = *(u64 *) _nodeidp;
212 if (get_node_id(inode) == nodeid) 212 if (get_node_id(inode) == nodeid)
@@ -257,6 +257,31 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
257 return inode; 257 return inode;
258} 258}
259 259
260int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
261 loff_t offset, loff_t len)
262{
263 struct inode *inode;
264 pgoff_t pg_start;
265 pgoff_t pg_end;
266
267 inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
268 if (!inode)
269 return -ENOENT;
270
271 fuse_invalidate_attr(inode);
272 if (offset >= 0) {
273 pg_start = offset >> PAGE_CACHE_SHIFT;
274 if (len <= 0)
275 pg_end = -1;
276 else
277 pg_end = (offset + len - 1) >> PAGE_CACHE_SHIFT;
278 invalidate_inode_pages2_range(inode->i_mapping,
279 pg_start, pg_end);
280 }
281 iput(inode);
282 return 0;
283}
284
260static void fuse_umount_begin(struct super_block *sb) 285static void fuse_umount_begin(struct super_block *sb)
261{ 286{
262 fuse_abort_conn(get_fuse_conn_super(sb)); 287 fuse_abort_conn(get_fuse_conn_super(sb));
@@ -480,6 +505,7 @@ void fuse_conn_init(struct fuse_conn *fc)
480 memset(fc, 0, sizeof(*fc)); 505 memset(fc, 0, sizeof(*fc));
481 spin_lock_init(&fc->lock); 506 spin_lock_init(&fc->lock);
482 mutex_init(&fc->inst_mutex); 507 mutex_init(&fc->inst_mutex);
508 init_rwsem(&fc->killsb);
483 atomic_set(&fc->count, 1); 509 atomic_set(&fc->count, 1);
484 init_waitqueue_head(&fc->waitq); 510 init_waitqueue_head(&fc->waitq);
485 init_waitqueue_head(&fc->blocked_waitq); 511 init_waitqueue_head(&fc->blocked_waitq);
@@ -862,6 +888,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
862 fuse_conn_init(fc); 888 fuse_conn_init(fc);
863 889
864 fc->dev = sb->s_dev; 890 fc->dev = sb->s_dev;
891 fc->sb = sb;
865 err = fuse_bdi_init(fc, sb); 892 err = fuse_bdi_init(fc, sb);
866 if (err) 893 if (err)
867 goto err_put_conn; 894 goto err_put_conn;
@@ -948,12 +975,25 @@ static int fuse_get_sb(struct file_system_type *fs_type,
948 return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); 975 return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
949} 976}
950 977
978static void fuse_kill_sb_anon(struct super_block *sb)
979{
980 struct fuse_conn *fc = get_fuse_conn_super(sb);
981
982 if (fc) {
983 down_write(&fc->killsb);
984 fc->sb = NULL;
985 up_write(&fc->killsb);
986 }
987
988 kill_anon_super(sb);
989}
990
951static struct file_system_type fuse_fs_type = { 991static struct file_system_type fuse_fs_type = {
952 .owner = THIS_MODULE, 992 .owner = THIS_MODULE,
953 .name = "fuse", 993 .name = "fuse",
954 .fs_flags = FS_HAS_SUBTYPE, 994 .fs_flags = FS_HAS_SUBTYPE,
955 .get_sb = fuse_get_sb, 995 .get_sb = fuse_get_sb,
956 .kill_sb = kill_anon_super, 996 .kill_sb = fuse_kill_sb_anon,
957}; 997};
958 998
959#ifdef CONFIG_BLOCK 999#ifdef CONFIG_BLOCK
@@ -965,11 +1005,24 @@ static int fuse_get_sb_blk(struct file_system_type *fs_type,
965 mnt); 1005 mnt);
966} 1006}
967 1007
1008static void fuse_kill_sb_blk(struct super_block *sb)
1009{
1010 struct fuse_conn *fc = get_fuse_conn_super(sb);
1011
1012 if (fc) {
1013 down_write(&fc->killsb);
1014 fc->sb = NULL;
1015 up_write(&fc->killsb);
1016 }
1017
1018 kill_block_super(sb);
1019}
1020
968static struct file_system_type fuseblk_fs_type = { 1021static struct file_system_type fuseblk_fs_type = {
969 .owner = THIS_MODULE, 1022 .owner = THIS_MODULE,
970 .name = "fuseblk", 1023 .name = "fuseblk",
971 .get_sb = fuse_get_sb_blk, 1024 .get_sb = fuse_get_sb_blk,
972 .kill_sb = kill_block_super, 1025 .kill_sb = fuse_kill_sb_blk,
973 .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE, 1026 .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
974}; 1027};
975 1028
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index e2b816a62488..cf593bf9fd32 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -28,6 +28,8 @@
28 * 28 *
29 * 7.12 29 * 7.12
30 * - add umask flag to input argument of open, mknod and mkdir 30 * - add umask flag to input argument of open, mknod and mkdir
31 * - add notification messages for invalidation of inodes and
32 * directory entries
31 */ 33 */
32 34
33#ifndef _LINUX_FUSE_H 35#ifndef _LINUX_FUSE_H
@@ -229,6 +231,8 @@ enum fuse_opcode {
229 231
230enum fuse_notify_code { 232enum fuse_notify_code {
231 FUSE_NOTIFY_POLL = 1, 233 FUSE_NOTIFY_POLL = 1,
234 FUSE_NOTIFY_INVAL_INODE = 2,
235 FUSE_NOTIFY_INVAL_ENTRY = 3,
232 FUSE_NOTIFY_CODE_MAX, 236 FUSE_NOTIFY_CODE_MAX,
233}; 237};
234 238
@@ -524,4 +528,16 @@ struct fuse_dirent {
524#define FUSE_DIRENT_SIZE(d) \ 528#define FUSE_DIRENT_SIZE(d) \
525 FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) 529 FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
526 530
531struct fuse_notify_inval_inode_out {
532 __u64 ino;
533 __s64 off;
534 __s64 len;
535};
536
537struct fuse_notify_inval_entry_out {
538 __u64 parent;
539 __u32 namelen;
540 __u32 padding;
541};
542
527#endif /* _LINUX_FUSE_H */ 543#endif /* _LINUX_FUSE_H */