diff options
author | Jan Kara <jack@suse.cz> | 2017-03-14 11:11:23 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2017-04-10 11:37:35 -0400 |
commit | 755b5bc681eb46de7bfaec196f85e30efd95bd9f (patch) | |
tree | 1fc0f867ae0e8edf6f672f43ed8f86ab658197f0 /fs/notify/mark.c | |
parent | e911d8af87dba7642138f4320ca3db80629989f2 (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.c | 66 |
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 | ||
321 | static int fsnotify_attach_connector_to_object( | 321 | static 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 | */ |
355 | int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp, | 361 | static 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); |
396 | added: | 419 | added: |
397 | mark->connector = conn; | 420 | mark->connector = conn; |
398 | return 0; | 421 | out_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; |
448 | err: | 468 | err: |