aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/dev.c88
-rw-r--r--fs/fuse/file.c2
-rw-r--r--fs/fuse/fuse_i.h2
-rw-r--r--include/linux/fuse.h13
4 files changed, 103 insertions, 2 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 7eb80d33c4f3..8e01c865586e 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1231,6 +1231,91 @@ err:
1231 return err; 1231 return err;
1232} 1232}
1233 1233
1234static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
1235 struct fuse_copy_state *cs)
1236{
1237 struct fuse_notify_store_out outarg;
1238 struct inode *inode;
1239 struct address_space *mapping;
1240 u64 nodeid;
1241 int err;
1242 pgoff_t index;
1243 unsigned int offset;
1244 unsigned int num;
1245 loff_t file_size;
1246 loff_t end;
1247
1248 err = -EINVAL;
1249 if (size < sizeof(outarg))
1250 goto out_finish;
1251
1252 err = fuse_copy_one(cs, &outarg, sizeof(outarg));
1253 if (err)
1254 goto out_finish;
1255
1256 err = -EINVAL;
1257 if (size - sizeof(outarg) != outarg.size)
1258 goto out_finish;
1259
1260 nodeid = outarg.nodeid;
1261
1262 down_read(&fc->killsb);
1263
1264 err = -ENOENT;
1265 if (!fc->sb)
1266 goto out_up_killsb;
1267
1268 inode = ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid);
1269 if (!inode)
1270 goto out_up_killsb;
1271
1272 mapping = inode->i_mapping;
1273 index = outarg.offset >> PAGE_CACHE_SHIFT;
1274 offset = outarg.offset & ~PAGE_CACHE_MASK;
1275 file_size = i_size_read(inode);
1276 end = outarg.offset + outarg.size;
1277 if (end > file_size) {
1278 file_size = end;
1279 fuse_write_update_size(inode, file_size);
1280 }
1281
1282 num = outarg.size;
1283 while (num) {
1284 struct page *page;
1285 unsigned int this_num;
1286
1287 err = -ENOMEM;
1288 page = find_or_create_page(mapping, index,
1289 mapping_gfp_mask(mapping));
1290 if (!page)
1291 goto out_iput;
1292
1293 this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
1294 err = fuse_copy_page(cs, &page, offset, this_num, 0);
1295 if (!err && offset == 0 && (num != 0 || file_size == end))
1296 SetPageUptodate(page);
1297 unlock_page(page);
1298 page_cache_release(page);
1299
1300 if (err)
1301 goto out_iput;
1302
1303 num -= this_num;
1304 offset = 0;
1305 index++;
1306 }
1307
1308 err = 0;
1309
1310out_iput:
1311 iput(inode);
1312out_up_killsb:
1313 up_read(&fc->killsb);
1314out_finish:
1315 fuse_copy_finish(cs);
1316 return err;
1317}
1318
1234static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, 1319static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
1235 unsigned int size, struct fuse_copy_state *cs) 1320 unsigned int size, struct fuse_copy_state *cs)
1236{ 1321{
@@ -1244,6 +1329,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
1244 case FUSE_NOTIFY_INVAL_ENTRY: 1329 case FUSE_NOTIFY_INVAL_ENTRY:
1245 return fuse_notify_inval_entry(fc, size, cs); 1330 return fuse_notify_inval_entry(fc, size, cs);
1246 1331
1332 case FUSE_NOTIFY_STORE:
1333 return fuse_notify_store(fc, size, cs);
1334
1247 default: 1335 default:
1248 fuse_copy_finish(cs); 1336 fuse_copy_finish(cs);
1249 return -EINVAL; 1337 return -EINVAL;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index ada0adeb3bb5..147c1f71bdb9 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -706,7 +706,7 @@ static int fuse_write_begin(struct file *file, struct address_space *mapping,
706 return 0; 706 return 0;
707} 707}
708 708
709static void fuse_write_update_size(struct inode *inode, loff_t pos) 709void fuse_write_update_size(struct inode *inode, loff_t pos)
710{ 710{
711 struct fuse_conn *fc = get_fuse_conn(inode); 711 struct fuse_conn *fc = get_fuse_conn(inode);
712 struct fuse_inode *fi = get_fuse_inode(inode); 712 struct fuse_inode *fi = get_fuse_inode(inode);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 8f309f04064e..61267d8d527b 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -748,4 +748,6 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
748unsigned fuse_file_poll(struct file *file, poll_table *wait); 748unsigned fuse_file_poll(struct file *file, poll_table *wait);
749int fuse_dev_release(struct inode *inode, struct file *file); 749int fuse_dev_release(struct inode *inode, struct file *file);
750 750
751void fuse_write_update_size(struct inode *inode, loff_t pos);
752
751#endif /* _FS_FUSE_I_H */ 753#endif /* _FS_FUSE_I_H */
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 88e0eb596919..a90bd49834aa 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -37,6 +37,9 @@
37 * 37 *
38 * 7.14 38 * 7.14
39 * - add splice support to fuse device 39 * - add splice support to fuse device
40 *
41 * 7.15
42 * - add store notify
40 */ 43 */
41 44
42#ifndef _LINUX_FUSE_H 45#ifndef _LINUX_FUSE_H
@@ -68,7 +71,7 @@
68#define FUSE_KERNEL_VERSION 7 71#define FUSE_KERNEL_VERSION 7
69 72
70/** Minor version number of this interface */ 73/** Minor version number of this interface */
71#define FUSE_KERNEL_MINOR_VERSION 14 74#define FUSE_KERNEL_MINOR_VERSION 15
72 75
73/** The node ID of the root inode */ 76/** The node ID of the root inode */
74#define FUSE_ROOT_ID 1 77#define FUSE_ROOT_ID 1
@@ -260,6 +263,7 @@ enum fuse_notify_code {
260 FUSE_NOTIFY_POLL = 1, 263 FUSE_NOTIFY_POLL = 1,
261 FUSE_NOTIFY_INVAL_INODE = 2, 264 FUSE_NOTIFY_INVAL_INODE = 2,
262 FUSE_NOTIFY_INVAL_ENTRY = 3, 265 FUSE_NOTIFY_INVAL_ENTRY = 3,
266 FUSE_NOTIFY_STORE = 4,
263 FUSE_NOTIFY_CODE_MAX, 267 FUSE_NOTIFY_CODE_MAX,
264}; 268};
265 269
@@ -568,4 +572,11 @@ struct fuse_notify_inval_entry_out {
568 __u32 padding; 572 __u32 padding;
569}; 573};
570 574
575struct fuse_notify_store_out {
576 __u64 nodeid;
577 __u64 offset;
578 __u32 size;
579 __u32 padding;
580};
581
571#endif /* _LINUX_FUSE_H */ 582#endif /* _LINUX_FUSE_H */