aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c88
1 files changed, 88 insertions, 0 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;