LCOV - code coverage report
Current view: top level - fs/notify - notification.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 56 65 86.2 %
Date: 2022-04-01 13:59:58 Functions: 8 8 100.0 %
Branches: 18 32 56.2 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
       4                 :            :  */
       5                 :            : 
       6                 :            : /*
       7                 :            :  * Basic idea behind the notification queue: An fsnotify group (like inotify)
       8                 :            :  * sends the userspace notification about events asynchronously some time after
       9                 :            :  * the event happened.  When inotify gets an event it will need to add that
      10                 :            :  * event to the group notify queue.  Since a single event might need to be on
      11                 :            :  * multiple group's notification queues we can't add the event directly to each
      12                 :            :  * queue and instead add a small "event_holder" to each queue.  This event_holder
      13                 :            :  * has a pointer back to the original event.  Since the majority of events are
      14                 :            :  * going to end up on one, and only one, notification queue we embed one
      15                 :            :  * event_holder into each event.  This means we have a single allocation instead
      16                 :            :  * of always needing two.  If the embedded event_holder is already in use by
      17                 :            :  * another group a new event_holder (from fsnotify_event_holder_cachep) will be
      18                 :            :  * allocated and used.
      19                 :            :  */
      20                 :            : 
      21                 :            : #include <linux/fs.h>
      22                 :            : #include <linux/init.h>
      23                 :            : #include <linux/kernel.h>
      24                 :            : #include <linux/list.h>
      25                 :            : #include <linux/module.h>
      26                 :            : #include <linux/mount.h>
      27                 :            : #include <linux/mutex.h>
      28                 :            : #include <linux/namei.h>
      29                 :            : #include <linux/path.h>
      30                 :            : #include <linux/slab.h>
      31                 :            : #include <linux/spinlock.h>
      32                 :            : 
      33                 :            : #include <linux/atomic.h>
      34                 :            : 
      35                 :            : #include <linux/fsnotify_backend.h>
      36                 :            : #include "fsnotify.h"
      37                 :            : 
      38                 :            : static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0);
      39                 :            : 
      40                 :            : /**
      41                 :            :  * fsnotify_get_cookie - return a unique cookie for use in synchronizing events.
      42                 :            :  * Called from fsnotify_move, which is inlined into filesystem modules.
      43                 :            :  */
      44                 :      18240 : u32 fsnotify_get_cookie(void)
      45                 :            : {
      46                 :      18240 :         return atomic_inc_return(&fsnotify_sync_cookie);
      47                 :            : }
      48                 :            : EXPORT_SYMBOL_GPL(fsnotify_get_cookie);
      49                 :            : 
      50                 :            : /* return true if the notify queue is empty, false otherwise */
      51                 :      23660 : bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group)
      52                 :            : {
      53         [ -  + ]:      23660 :         assert_spin_locked(&group->notification_lock);
      54                 :      23660 :         return list_empty(&group->notification_list) ? true : false;
      55                 :            : }
      56                 :            : 
      57                 :       6040 : void fsnotify_destroy_event(struct fsnotify_group *group,
      58                 :            :                             struct fsnotify_event *event)
      59                 :            : {
      60                 :            :         /* Overflow events are per-group and we don't want to free them */
      61   [ +  -  +  - ]:       6040 :         if (!event || event == group->overflow_event)
      62                 :            :                 return;
      63                 :            :         /*
      64                 :            :          * If the event is still queued, we have a problem... Do an unreliable
      65                 :            :          * lockless check first to avoid locking in the common case. The
      66                 :            :          * locking may be necessary for permission events which got removed
      67                 :            :          * from the list by a different CPU than the one freeing the event.
      68                 :            :          */
      69         [ -  + ]:       6040 :         if (!list_empty(&event->list)) {
      70                 :          0 :                 spin_lock(&group->notification_lock);
      71         [ #  # ]:          0 :                 WARN_ON(!list_empty(&event->list));
      72                 :          0 :                 spin_unlock(&group->notification_lock);
      73                 :            :         }
      74                 :       6040 :         group->ops->free_event(event);
      75                 :            : }
      76                 :            : 
      77                 :            : /*
      78                 :            :  * Add an event to the group notification queue.  The group can later pull this
      79                 :            :  * event off the queue to deal with.  The function returns 0 if the event was
      80                 :            :  * added to the queue, 1 if the event was merged with some other queued event,
      81                 :            :  * 2 if the event was not queued - either the queue of events has overflown
      82                 :            :  * or the group is shutting down.
      83                 :            :  */
      84                 :       6040 : int fsnotify_add_event(struct fsnotify_group *group,
      85                 :            :                        struct fsnotify_event *event,
      86                 :            :                        int (*merge)(struct list_head *,
      87                 :            :                                     struct fsnotify_event *))
      88                 :            : {
      89                 :       6040 :         int ret = 0;
      90                 :       6040 :         struct list_head *list = &group->notification_list;
      91                 :            : 
      92                 :       6040 :         pr_debug("%s: group=%p event=%p\n", __func__, group, event);
      93                 :            : 
      94                 :       6040 :         spin_lock(&group->notification_lock);
      95                 :            : 
      96         [ +  + ]:       6040 :         if (group->shutdown) {
      97                 :         78 :                 spin_unlock(&group->notification_lock);
      98                 :         78 :                 return 2;
      99                 :            :         }
     100                 :            : 
     101         [ +  - ]:       5962 :         if (event == group->overflow_event ||
     102         [ -  + ]:       5962 :             group->q_len >= group->max_events) {
     103                 :          0 :                 ret = 2;
     104                 :            :                 /* Queue overflow event only if it isn't already queued */
     105         [ #  # ]:          0 :                 if (!list_empty(&group->overflow_event->list)) {
     106                 :          0 :                         spin_unlock(&group->notification_lock);
     107                 :          0 :                         return ret;
     108                 :            :                 }
     109                 :          0 :                 event = group->overflow_event;
     110                 :          0 :                 goto queue;
     111                 :            :         }
     112                 :            : 
     113   [ +  +  -  + ]:       5962 :         if (!list_empty(list) && merge) {
     114                 :       3172 :                 ret = merge(list, event);
     115         [ +  + ]:       3172 :                 if (ret) {
     116                 :          9 :                         spin_unlock(&group->notification_lock);
     117                 :          9 :                         return ret;
     118                 :            :                 }
     119                 :            :         }
     120                 :            : 
     121                 :       5953 : queue:
     122                 :       5953 :         group->q_len++;
     123                 :       5953 :         list_add_tail(&event->list, list);
     124                 :       5953 :         spin_unlock(&group->notification_lock);
     125                 :            : 
     126                 :       5953 :         wake_up(&group->notification_waitq);
     127                 :       5953 :         kill_fasync(&group->fsn_fa, SIGIO, POLL_IN);
     128                 :       5953 :         return ret;
     129                 :            : }
     130                 :            : 
     131                 :       5953 : void fsnotify_remove_queued_event(struct fsnotify_group *group,
     132                 :            :                                   struct fsnotify_event *event)
     133                 :            : {
     134         [ -  + ]:       5953 :         assert_spin_locked(&group->notification_lock);
     135                 :            :         /*
     136                 :            :          * We need to init list head for the case of overflow event so that
     137                 :            :          * check in fsnotify_add_event() works
     138                 :            :          */
     139                 :       5953 :         list_del_init(&event->list);
     140                 :       5953 :         group->q_len--;
     141                 :       5953 : }
     142                 :            : 
     143                 :            : /*
     144                 :            :  * Remove and return the first event from the notification list.  It is the
     145                 :            :  * responsibility of the caller to destroy the obtained event
     146                 :            :  */
     147                 :       5953 : struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group)
     148                 :            : {
     149                 :       5953 :         struct fsnotify_event *event;
     150                 :            : 
     151         [ -  + ]:       5953 :         assert_spin_locked(&group->notification_lock);
     152                 :            : 
     153                 :       5953 :         pr_debug("%s: group=%p\n", __func__, group);
     154                 :            : 
     155                 :       5953 :         event = list_first_entry(&group->notification_list,
     156                 :            :                                  struct fsnotify_event, list);
     157                 :       5953 :         fsnotify_remove_queued_event(group, event);
     158                 :       5953 :         return event;
     159                 :            : }
     160                 :            : 
     161                 :            : /*
     162                 :            :  * This will not remove the event, that must be done with
     163                 :            :  * fsnotify_remove_first_event()
     164                 :            :  */
     165                 :       6020 : struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group)
     166                 :            : {
     167         [ -  + ]:       6020 :         assert_spin_locked(&group->notification_lock);
     168                 :            : 
     169                 :       6020 :         return list_first_entry(&group->notification_list,
     170                 :            :                                 struct fsnotify_event, list);
     171                 :            : }
     172                 :            : 
     173                 :            : /*
     174                 :            :  * Called when a group is being torn down to clean up any outstanding
     175                 :            :  * event notifications.
     176                 :            :  */
     177                 :        156 : void fsnotify_flush_notify(struct fsnotify_group *group)
     178                 :            : {
     179                 :        156 :         struct fsnotify_event *event;
     180                 :            : 
     181                 :        156 :         spin_lock(&group->notification_lock);
     182         [ +  + ]:        234 :         while (!fsnotify_notify_queue_is_empty(group)) {
     183                 :         78 :                 event = fsnotify_remove_first_event(group);
     184                 :         78 :                 spin_unlock(&group->notification_lock);
     185                 :         78 :                 fsnotify_destroy_event(group, event);
     186                 :         78 :                 spin_lock(&group->notification_lock);
     187                 :            :         }
     188                 :        156 :         spin_unlock(&group->notification_lock);
     189                 :        156 : }

Generated by: LCOV version 1.14