aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/fanotify
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-12-17 21:24:28 -0500
committerEric Paris <eparis@redhat.com>2010-07-28 09:58:57 -0400
commit88826276dcaf4cef9cc7c2695ff15c6d20d4a74d (patch)
treebb90774f639a1b69546e8f0504a8e9c76582de94 /fs/notify/fanotify
parent1c529063a3e4c15eaae28db31326a7aaab7091b5 (diff)
fanotify: infrastructure to add an remove marks on vfsmounts
infrastructure work to add and remove marks on vfsmounts. This should get every set up except wiring the functions to the syscalls. Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'fs/notify/fanotify')
-rw-r--r--fs/notify/fanotify/fanotify_user.c185
1 files changed, 133 insertions, 52 deletions
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 05351936a725..cb7a0c5ff854 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -295,31 +295,83 @@ out:
295 return ret; 295 return ret;
296} 296}
297 297
298static int fanotify_remove_mark(struct fsnotify_group *group, 298static void fanotify_update_object_mask(struct fsnotify_group *group,
299 struct inode *inode, 299 struct inode *inode,
300 __u32 mask) 300 struct vfsmount *mnt,
301 struct fsnotify_mark *fsn_mark,
302 unsigned int flags,
303 __u32 mask)
301{ 304{
302 struct fsnotify_mark *fsn_mark; 305 __u32 old_mask, new_mask;
303 __u32 new_mask;
304
305 pr_debug("%s: group=%p inode=%p mask=%x\n", __func__,
306 group, inode, mask);
307 306
308 fsn_mark = fsnotify_find_inode_mark(group, inode); 307 pr_debug("%s: group=%p inode=%p mnt=%p fsn_mark=%p flags=%x mask=%x\n",
309 if (!fsn_mark) 308 __func__, group, inode, mnt, fsn_mark, flags, mask);
310 return -ENOENT;
311 309
312 spin_lock(&fsn_mark->lock); 310 spin_lock(&fsn_mark->lock);
313 fsn_mark->mask &= ~mask; 311 old_mask = fsn_mark->mask;
312 if (flags & FAN_MARK_ADD)
313 fsn_mark->mask |= mask;
314 else if (flags & FAN_MARK_REMOVE)
315 fsn_mark->mask &= ~mask;
316 else
317 BUG();
314 new_mask = fsn_mark->mask; 318 new_mask = fsn_mark->mask;
315 spin_unlock(&fsn_mark->lock); 319 spin_unlock(&fsn_mark->lock);
316 320
317 if (!new_mask) 321 if (!new_mask)
318 fsnotify_destroy_mark(fsn_mark); 322 fsnotify_destroy_mark(fsn_mark);
323
324 /* we made changes to a mask, update the group mask and the object mask
325 * so things happen quickly. */
326 if (old_mask != new_mask) {
327 __u32 dropped, do_object, do_group;
328
329 /* more bits in old than in new? */
330 dropped = (old_mask & ~new_mask);
331 /* more bits in this fsn_mark than the group? */
332 do_group = (new_mask & ~group->mask);
333
334 if (inode) {
335 /* more bits in this fsn_mark than the object's mask? */
336 do_object = (new_mask & ~inode->i_fsnotify_mask);
337 /* update the object with this new fsn_mark */
338 if (dropped || do_object)
339 fsnotify_recalc_inode_mask(inode);
340 } else if (mnt) {
341 /* more bits in this fsn_mark than the object's mask? */
342 do_object = (new_mask & ~mnt->mnt_fsnotify_mask);
343 /* update the object with this new fsn_mark */
344 if (dropped || do_object)
345 fsnotify_recalc_vfsmount_mask(mnt);
346 } else {
347 BUG();
348 }
349
350 /* update the group mask with the new mask */
351 if (dropped || do_group)
352 fsnotify_recalc_group_mask(group);
353 }
354}
355
356static int fanotify_remove_mark(struct fsnotify_group *group, struct inode *inode,
357 struct vfsmount *mnt, unsigned int flags, __u32 mask)
358{
359 struct fsnotify_mark *fsn_mark = NULL;
360
361 BUG_ON(inode && mnt);
362 BUG_ON(!inode && !mnt);
363
364 if (inode)
365 fsn_mark = fsnotify_find_inode_mark(group, inode);
366 else if (mnt)
367 fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
319 else 368 else
320 fsnotify_recalc_inode_mask(inode); 369 BUG();
321 370
322 fsnotify_recalc_group_mask(group); 371 if (!fsn_mark)
372 return -ENOENT;
373
374 fanotify_update_object_mask(group, inode, mnt, fsn_mark, flags, mask);
323 375
324 /* matches the fsnotify_find_inode_mark() */ 376 /* matches the fsnotify_find_inode_mark() */
325 fsnotify_put_mark(fsn_mark); 377 fsnotify_put_mark(fsn_mark);
@@ -327,22 +379,48 @@ static int fanotify_remove_mark(struct fsnotify_group *group,
327 return 0; 379 return 0;
328} 380}
329 381
330static int fanotify_add_mark(struct fsnotify_group *group, 382static struct fsnotify_mark *fanotify_add_vfsmount_mark(struct fsnotify_group *group,
331 struct inode *inode, 383 struct vfsmount *mnt)
332 __u32 mask)
333{ 384{
334 struct fsnotify_mark *fsn_mark; 385 struct fsnotify_mark *fsn_mark;
335 __u32 old_mask, new_mask;
336 int ret;
337 386
338 pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, 387 fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
339 group, inode, mask); 388 if (!fsn_mark) {
389 struct fsnotify_mark *new_fsn_mark;
390 int ret;
391
392 fsn_mark = ERR_PTR(-ENOMEM);
393 new_fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
394 if (!new_fsn_mark)
395 goto out;
396
397 fsnotify_init_mark(new_fsn_mark, fanotify_free_mark);
398 ret = fsnotify_add_mark(new_fsn_mark, group, NULL, mnt, 0);
399 if (ret) {
400 fsn_mark = ERR_PTR(ret);
401 fanotify_free_mark(new_fsn_mark);
402 goto out;
403 }
404
405 fsn_mark = new_fsn_mark;
406 }
407out:
408 return fsn_mark;
409}
410
411static struct fsnotify_mark *fanotify_add_inode_mark(struct fsnotify_group *group,
412 struct inode *inode)
413{
414 struct fsnotify_mark *fsn_mark;
415
416 pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
340 417
341 fsn_mark = fsnotify_find_inode_mark(group, inode); 418 fsn_mark = fsnotify_find_inode_mark(group, inode);
342 if (!fsn_mark) { 419 if (!fsn_mark) {
343 struct fsnotify_mark *new_fsn_mark; 420 struct fsnotify_mark *new_fsn_mark;
421 int ret;
344 422
345 ret = -ENOMEM; 423 fsn_mark = ERR_PTR(-ENOMEM);
346 new_fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL); 424 new_fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
347 if (!new_fsn_mark) 425 if (!new_fsn_mark)
348 goto out; 426 goto out;
@@ -350,57 +428,60 @@ static int fanotify_add_mark(struct fsnotify_group *group,
350 fsnotify_init_mark(new_fsn_mark, fanotify_free_mark); 428 fsnotify_init_mark(new_fsn_mark, fanotify_free_mark);
351 ret = fsnotify_add_mark(new_fsn_mark, group, inode, NULL, 0); 429 ret = fsnotify_add_mark(new_fsn_mark, group, inode, NULL, 0);
352 if (ret) { 430 if (ret) {
431 fsn_mark = ERR_PTR(ret);
353 fanotify_free_mark(new_fsn_mark); 432 fanotify_free_mark(new_fsn_mark);
354 goto out; 433 goto out;
355 } 434 }
356 435
357 fsn_mark = new_fsn_mark; 436 fsn_mark = new_fsn_mark;
358 } 437 }
438out:
439 return fsn_mark;
440}
359 441
360 ret = 0; 442static int fanotify_add_mark(struct fsnotify_group *group, struct inode *inode,
443 struct vfsmount *mnt, unsigned int flags, __u32 mask)
444{
445 struct fsnotify_mark *fsn_mark;
361 446
362 spin_lock(&fsn_mark->lock); 447 pr_debug("%s: group=%p inode=%p mnt=%p flags=%x mask=%x\n",
363 old_mask = fsn_mark->mask; 448 __func__, group, inode, mnt, flags, mask);
364 fsn_mark->mask |= mask;
365 new_mask = fsn_mark->mask;
366 spin_unlock(&fsn_mark->lock);
367 449
368 /* we made changes to a mask, update the group mask and the inode mask 450 BUG_ON(inode && mnt);
369 * so things happen quickly. */ 451 BUG_ON(!inode && !mnt);
370 if (old_mask != new_mask) {
371 /* more bits in old than in new? */
372 int dropped = (old_mask & ~new_mask);
373 /* more bits in this mark than the inode's mask? */
374 int do_inode = (new_mask & ~inode->i_fsnotify_mask);
375 /* more bits in this mark than the group? */
376 int do_group = (new_mask & ~group->mask);
377 452
378 /* update the inode with this new mark */ 453 if (inode)
379 if (dropped || do_inode) 454 fsn_mark = fanotify_add_inode_mark(group, inode);
380 fsnotify_recalc_inode_mask(inode); 455 else if (mnt)
456 fsn_mark = fanotify_add_vfsmount_mark(group, mnt);
457 else
458 BUG();
381 459
382 /* update the group mask with the new mask */ 460 if (IS_ERR(fsn_mark))
383 if (dropped || do_group) 461 goto out;
384 fsnotify_recalc_group_mask(group); 462
385 } 463 fanotify_update_object_mask(group, inode, mnt, fsn_mark, flags, mask);
386 464
387 /* match the init or the find.... */ 465 /* match the init or the find.... */
388 fsnotify_put_mark(fsn_mark); 466 fsnotify_put_mark(fsn_mark);
389out: 467out:
390 return ret; 468 return PTR_ERR(fsn_mark);
391} 469}
392 470
393static int fanotify_update_mark(struct fsnotify_group *group, 471static int fanotify_update_mark(struct fsnotify_group *group,
394 struct inode *inode, int flags, 472 struct inode *inode, struct vfsmount *mnt,
395 __u32 mask) 473 int flags, __u32 mask)
396{ 474{
397 pr_debug("%s: group=%p inode=%p flags=%x mask=%x\n", __func__, 475 pr_debug("%s: group=%p inode=%p mnt=%p flags=%x mask=%x\n",
398 group, inode, flags, mask); 476 __func__, group, inode, mnt, flags, mask);
477
478 BUG_ON(inode && mnt);
479 BUG_ON(!inode && !mnt);
399 480
400 if (flags & FAN_MARK_ADD) 481 if (flags & FAN_MARK_ADD)
401 fanotify_add_mark(group, inode, mask); 482 fanotify_add_mark(group, inode, mnt, flags, mask);
402 else if (flags & FAN_MARK_REMOVE) 483 else if (flags & FAN_MARK_REMOVE)
403 fanotify_remove_mark(group, inode, mask); 484 fanotify_remove_mark(group, inode, mnt, flags, mask);
404 else 485 else
405 BUG(); 486 BUG();
406 487
@@ -502,7 +583,7 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
502 group = filp->private_data; 583 group = filp->private_data;
503 584
504 /* create/update an inode mark */ 585 /* create/update an inode mark */
505 ret = fanotify_update_mark(group, inode, flags, mask); 586 ret = fanotify_update_mark(group, inode, NULL, flags, mask);
506 587
507 path_put(&path); 588 path_put(&path);
508fput_and_out: 589fput_and_out: