diff options
-rw-r--r-- | fs/fuse/dev.c | 88 | ||||
-rw-r--r-- | fs/fuse/file.c | 2 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 2 | ||||
-rw-r--r-- | include/linux/fuse.h | 13 |
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 | ||
1234 | static 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 | |||
1310 | out_iput: | ||
1311 | iput(inode); | ||
1312 | out_up_killsb: | ||
1313 | up_read(&fc->killsb); | ||
1314 | out_finish: | ||
1315 | fuse_copy_finish(cs); | ||
1316 | return err; | ||
1317 | } | ||
1318 | |||
1234 | static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | 1319 | static 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 | ||
709 | static void fuse_write_update_size(struct inode *inode, loff_t pos) | 709 | void 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, | |||
748 | unsigned fuse_file_poll(struct file *file, poll_table *wait); | 748 | unsigned fuse_file_poll(struct file *file, poll_table *wait); |
749 | int fuse_dev_release(struct inode *inode, struct file *file); | 749 | int fuse_dev_release(struct inode *inode, struct file *file); |
750 | 750 | ||
751 | void 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 | ||
575 | struct 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 */ |