summaryrefslogtreecommitdiffstats
path: root/fs/notify/mark.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-03-14 11:11:23 -0400
committerJan Kara <jack@suse.cz>2017-04-10 11:37:35 -0400
commit755b5bc681eb46de7bfaec196f85e30efd95bd9f (patch)
tree1fc0f867ae0e8edf6f672f43ed8f86ab658197f0 /fs/notify/mark.c
parente911d8af87dba7642138f4320ca3db80629989f2 (diff)
fsnotify: Remove indirection from mark list addition
Adding notification mark to object list has been currently done through fsnotify_add_{inode|vfsmount}_mark() helpers from fsnotify_add_mark_locked() which call fsnotify_add_mark_list(). Remove this unnecessary indirection to simplify the code. Pushing all the locking to fsnotify_add_mark_list() also allows us to allocate the connector structure with GFP_KERNEL mode. Reviewed-by: Miklos Szeredi <mszeredi@redhat.com> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/notify/mark.c')
-rw-r--r--fs/notify/mark.c66
1 files changed, 43 insertions, 23 deletions
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index 8a15c64fbe80..e8c2f829ce65 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -320,12 +320,13 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
320 320
321static int fsnotify_attach_connector_to_object( 321static int fsnotify_attach_connector_to_object(
322 struct fsnotify_mark_connector **connp, 322 struct fsnotify_mark_connector **connp,
323 spinlock_t *lock,
323 struct inode *inode, 324 struct inode *inode,
324 struct vfsmount *mnt) 325 struct vfsmount *mnt)
325{ 326{
326 struct fsnotify_mark_connector *conn; 327 struct fsnotify_mark_connector *conn;
327 328
328 conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, GFP_ATOMIC); 329 conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, GFP_KERNEL);
329 if (!conn) 330 if (!conn)
330 return -ENOMEM; 331 return -ENOMEM;
331 INIT_HLIST_HEAD(&conn->list); 332 INIT_HLIST_HEAD(&conn->list);
@@ -341,7 +342,12 @@ static int fsnotify_attach_connector_to_object(
341 * lockless_dereference() in fsnotify(). 342 * lockless_dereference() in fsnotify().
342 */ 343 */
343 smp_wmb(); 344 smp_wmb();
344 *connp = conn; 345 spin_lock(lock);
346 if (!*connp)
347 *connp = conn;
348 else
349 kmem_cache_free(fsnotify_mark_connector_cachep, conn);
350 spin_unlock(lock);
345 351
346 return 0; 352 return 0;
347} 353}
@@ -352,20 +358,35 @@ static int fsnotify_attach_connector_to_object(
352 * to which group and for which inodes. These marks are ordered according to 358 * to which group and for which inodes. These marks are ordered according to
353 * priority, highest number first, and then by the group's location in memory. 359 * priority, highest number first, and then by the group's location in memory.
354 */ 360 */
355int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp, 361static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
356 struct fsnotify_mark *mark, struct inode *inode, 362 struct inode *inode, struct vfsmount *mnt,
357 struct vfsmount *mnt, int allow_dups) 363 int allow_dups)
358{ 364{
359 struct fsnotify_mark *lmark, *last = NULL; 365 struct fsnotify_mark *lmark, *last = NULL;
360 struct fsnotify_mark_connector *conn; 366 struct fsnotify_mark_connector *conn;
367 struct fsnotify_mark_connector **connp;
368 spinlock_t *lock;
361 int cmp; 369 int cmp;
362 int err; 370 int err = 0;
371
372 if (WARN_ON(!inode && !mnt))
373 return -EINVAL;
374 if (inode) {
375 connp = &inode->i_fsnotify_marks;
376 lock = &inode->i_lock;
377 } else {
378 connp = &real_mount(mnt)->mnt_fsnotify_marks;
379 lock = &mnt->mnt_root->d_lock;
380 }
363 381
364 if (!*connp) { 382 if (!*connp) {
365 err = fsnotify_attach_connector_to_object(connp, inode, mnt); 383 err = fsnotify_attach_connector_to_object(connp, lock,
384 inode, mnt);
366 if (err) 385 if (err)
367 return err; 386 return err;
368 } 387 }
388 spin_lock(&mark->lock);
389 spin_lock(lock);
369 conn = *connp; 390 conn = *connp;
370 391
371 /* is mark the first mark? */ 392 /* is mark the first mark? */
@@ -380,8 +401,10 @@ int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp,
380 hlist_for_each_entry(lmark, &conn->list, obj_list) { 401 hlist_for_each_entry(lmark, &conn->list, obj_list) {
381 last = lmark; 402 last = lmark;
382 403
383 if ((lmark->group == mark->group) && !allow_dups) 404 if ((lmark->group == mark->group) && !allow_dups) {
384 return -EEXIST; 405 err = -EEXIST;
406 goto out_err;
407 }
385 408
386 cmp = fsnotify_compare_groups(lmark->group, mark->group); 409 cmp = fsnotify_compare_groups(lmark->group, mark->group);
387 if (cmp >= 0) { 410 if (cmp >= 0) {
@@ -395,7 +418,10 @@ int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp,
395 hlist_add_behind_rcu(&mark->obj_list, &last->obj_list); 418 hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);
396added: 419added:
397 mark->connector = conn; 420 mark->connector = conn;
398 return 0; 421out_err:
422 spin_unlock(lock);
423 spin_unlock(&mark->lock);
424 return err;
399} 425}
400 426
401/* 427/*
@@ -427,22 +453,16 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
427 list_add(&mark->g_list, &group->marks_list); 453 list_add(&mark->g_list, &group->marks_list);
428 atomic_inc(&group->num_marks); 454 atomic_inc(&group->num_marks);
429 fsnotify_get_mark(mark); /* for i_list and g_list */ 455 fsnotify_get_mark(mark); /* for i_list and g_list */
430
431 if (inode) {
432 ret = fsnotify_add_inode_mark(mark, group, inode, allow_dups);
433 if (ret)
434 goto err;
435 } else if (mnt) {
436 ret = fsnotify_add_vfsmount_mark(mark, group, mnt, allow_dups);
437 if (ret)
438 goto err;
439 } else {
440 BUG();
441 }
442 spin_unlock(&mark->lock); 456 spin_unlock(&mark->lock);
443 457
458 ret = fsnotify_add_mark_list(mark, inode, mnt, allow_dups);
459 if (ret)
460 goto err;
461
444 if (inode) 462 if (inode)
445 __fsnotify_update_child_dentry_flags(inode); 463 fsnotify_recalc_inode_mask(inode);
464 else
465 fsnotify_recalc_vfsmount_mask(mnt);
446 466
447 return ret; 467 return ret;
448err: 468err: