Commit 3b463ae0c6264f70e5d4c0a9c46af20fed43c96e

Authored by John Muir
Committed by Miklos Szeredi
1 parent e0a43ddcc0

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>

Showing 5 changed files with 214 additions and 3 deletions Side-by-side Diff

... ... @@ -849,12 +849,93 @@
849 849 return err;
850 850 }
851 851  
  852 +static 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 +
  874 +err_unlock:
  875 + up_read(&fc->killsb);
  876 + return err;
  877 +
  878 +err:
  879 + fuse_copy_finish(cs);
  880 + return err;
  881 +}
  882 +
  883 +static 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 +
  918 +err_unlock:
  919 + up_read(&fc->killsb);
  920 + return err;
  921 +
  922 +err:
  923 + fuse_copy_finish(cs);
  924 + return err;
  925 +}
  926 +
852 927 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
853 928 unsigned int size, struct fuse_copy_state *cs)
854 929 {
855 930 switch (code) {
856 931 case FUSE_NOTIFY_POLL:
857 932 return fuse_notify_poll(fc, size, cs);
  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);
858 939  
859 940 default:
860 941 fuse_copy_finish(cs);
... ... @@ -859,6 +859,43 @@
859 859 return err;
860 860 }
861 861  
  862 +int 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 900 * Calling into a user-controlled filesystem gives the filesystem
864 901 * daemon ptrace-like capabilities over the requester process. This
... ... @@ -484,6 +484,12 @@
484 484  
485 485 /** Called on final put */
486 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  
489 495 static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
... ... @@ -512,6 +518,11 @@
512 518 extern const struct dentry_operations fuse_dentry_operations;
513 519  
514 520 /**
  521 + * Inode to nodeid comparison.
  522 + */
  523 +int fuse_inode_eq(struct inode *inode, void *_nodeidp);
  524 +
  525 +/**
515 526 * Get a filled in inode
516 527 */
517 528 struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
... ... @@ -710,6 +721,19 @@
710 721 void fuse_release_nowrite(struct inode *inode);
711 722  
712 723 u64 fuse_get_attr_version(struct fuse_conn *fc);
  724 +
  725 +/**
  726 + * File-system tells the kernel to invalidate cache for the given node id.
  727 + */
  728 +int 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 + */
  735 +int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
  736 + struct qstr *name);
713 737  
714 738 int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
715 739 bool isdir);
... ... @@ -206,7 +206,7 @@
206 206 BUG();
207 207 }
208 208  
209   -static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
  209 +int fuse_inode_eq(struct inode *inode, void *_nodeidp)
210 210 {
211 211 u64 nodeid = *(u64 *) _nodeidp;
212 212 if (get_node_id(inode) == nodeid)
... ... @@ -257,6 +257,31 @@
257 257 return inode;
258 258 }
259 259  
  260 +int 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 +
260 285 static void fuse_umount_begin(struct super_block *sb)
261 286 {
262 287 fuse_abort_conn(get_fuse_conn_super(sb));
... ... @@ -480,6 +505,7 @@
480 505 memset(fc, 0, sizeof(*fc));
481 506 spin_lock_init(&fc->lock);
482 507 mutex_init(&fc->inst_mutex);
  508 + init_rwsem(&fc->killsb);
483 509 atomic_set(&fc->count, 1);
484 510 init_waitqueue_head(&fc->waitq);
485 511 init_waitqueue_head(&fc->blocked_waitq);
... ... @@ -862,6 +888,7 @@
862 888 fuse_conn_init(fc);
863 889  
864 890 fc->dev = sb->s_dev;
  891 + fc->sb = sb;
865 892 err = fuse_bdi_init(fc, sb);
866 893 if (err)
867 894 goto err_put_conn;
868 895  
... ... @@ -948,12 +975,25 @@
948 975 return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
949 976 }
950 977  
  978 +static 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 +
951 991 static struct file_system_type fuse_fs_type = {
952 992 .owner = THIS_MODULE,
953 993 .name = "fuse",
954 994 .fs_flags = FS_HAS_SUBTYPE,
955 995 .get_sb = fuse_get_sb,
956   - .kill_sb = kill_anon_super,
  996 + .kill_sb = fuse_kill_sb_anon,
957 997 };
958 998  
959 999 #ifdef CONFIG_BLOCK
960 1000  
... ... @@ -965,11 +1005,24 @@
965 1005 mnt);
966 1006 }
967 1007  
  1008 +static 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 +
968 1021 static struct file_system_type fuseblk_fs_type = {
969 1022 .owner = THIS_MODULE,
970 1023 .name = "fuseblk",
971 1024 .get_sb = fuse_get_sb_blk,
972   - .kill_sb = kill_block_super,
  1025 + .kill_sb = fuse_kill_sb_blk,
973 1026 .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
974 1027 };
975 1028  
include/linux/fuse.h
... ... @@ -28,6 +28,8 @@
28 28 *
29 29 * 7.12
30 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 35 #ifndef _LINUX_FUSE_H
... ... @@ -229,6 +231,8 @@
229 231  
230 232 enum fuse_notify_code {
231 233 FUSE_NOTIFY_POLL = 1,
  234 + FUSE_NOTIFY_INVAL_INODE = 2,
  235 + FUSE_NOTIFY_INVAL_ENTRY = 3,
232 236 FUSE_NOTIFY_CODE_MAX,
233 237 };
234 238  
... ... @@ -523,6 +527,18 @@
523 527 #define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
524 528 #define FUSE_DIRENT_SIZE(d) \
525 529 FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
  530 +
  531 +struct fuse_notify_inval_inode_out {
  532 + __u64 ino;
  533 + __s64 off;
  534 + __s64 len;
  535 +};
  536 +
  537 +struct fuse_notify_inval_entry_out {
  538 + __u64 parent;
  539 + __u32 namelen;
  540 + __u32 padding;
  541 +};
526 542  
527 543 #endif /* _LINUX_FUSE_H */