return err;
 }
 
+static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
+                            struct fuse_copy_state *cs)
+{
+       struct fuse_notify_store_out outarg;
+       struct inode *inode;
+       struct address_space *mapping;
+       u64 nodeid;
+       int err;
+       pgoff_t index;
+       unsigned int offset;
+       unsigned int num;
+       loff_t file_size;
+       loff_t end;
+
+       err = -EINVAL;
+       if (size < sizeof(outarg))
+               goto out_finish;
+
+       err = fuse_copy_one(cs, &outarg, sizeof(outarg));
+       if (err)
+               goto out_finish;
+
+       err = -EINVAL;
+       if (size - sizeof(outarg) != outarg.size)
+               goto out_finish;
+
+       nodeid = outarg.nodeid;
+
+       down_read(&fc->killsb);
+
+       err = -ENOENT;
+       if (!fc->sb)
+               goto out_up_killsb;
+
+       inode = ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid);
+       if (!inode)
+               goto out_up_killsb;
+
+       mapping = inode->i_mapping;
+       index = outarg.offset >> PAGE_CACHE_SHIFT;
+       offset = outarg.offset & ~PAGE_CACHE_MASK;
+       file_size = i_size_read(inode);
+       end = outarg.offset + outarg.size;
+       if (end > file_size) {
+               file_size = end;
+               fuse_write_update_size(inode, file_size);
+       }
+
+       num = outarg.size;
+       while (num) {
+               struct page *page;
+               unsigned int this_num;
+
+               err = -ENOMEM;
+               page = find_or_create_page(mapping, index,
+                                          mapping_gfp_mask(mapping));
+               if (!page)
+                       goto out_iput;
+
+               this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
+               err = fuse_copy_page(cs, &page, offset, this_num, 0);
+               if (!err && offset == 0 && (num != 0 || file_size == end))
+                       SetPageUptodate(page);
+               unlock_page(page);
+               page_cache_release(page);
+
+               if (err)
+                       goto out_iput;
+
+               num -= this_num;
+               offset = 0;
+               index++;
+       }
+
+       err = 0;
+
+out_iput:
+       iput(inode);
+out_up_killsb:
+       up_read(&fc->killsb);
+out_finish:
+       fuse_copy_finish(cs);
+       return err;
+}
+
 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
                       unsigned int size, struct fuse_copy_state *cs)
 {
        case FUSE_NOTIFY_INVAL_ENTRY:
                return fuse_notify_inval_entry(fc, size, cs);
 
+       case FUSE_NOTIFY_STORE:
+               return fuse_notify_store(fc, size, cs);
+
        default:
                fuse_copy_finish(cs);
                return -EINVAL;
 
  *
  * 7.14
  *  - add splice support to fuse device
+ *
+ * 7.15
+ *  - add store notify
  */
 
 #ifndef _LINUX_FUSE_H
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 14
+#define FUSE_KERNEL_MINOR_VERSION 15
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
        FUSE_NOTIFY_POLL   = 1,
        FUSE_NOTIFY_INVAL_INODE = 2,
        FUSE_NOTIFY_INVAL_ENTRY = 3,
+       FUSE_NOTIFY_STORE = 4,
        FUSE_NOTIFY_CODE_MAX,
 };
 
        __u32   padding;
 };
 
+struct fuse_notify_store_out {
+       __u64   nodeid;
+       __u64   offset;
+       __u32   size;
+       __u32   padding;
+};
+
 #endif /* _LINUX_FUSE_H */