diff options
Diffstat (limited to 'fs/fuse')
-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 |
3 files changed, 91 insertions, 1 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 */ |