1 /* 2 * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2, or (at your option) 7 * any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; see the file COPYING. If not, write to 16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19 #include <linux/list.h> 20 #include <linux/mutex.h> 21 #include <linux/slab.h> 22 #include <linux/srcu.h> 23 #include <linux/rculist.h> 24 #include <linux/wait.h> 25 26 #include <linux/fsnotify_backend.h> 27 #include "fsnotify.h" 28 29 #include <asm/atomic.h> 30 31 /* 32 * Final freeing of a group 33 */ 34 void fsnotify_final_destroy_group(struct fsnotify_group *group) 35 { 36 /* clear the notification queue of all events */ 37 fsnotify_flush_notify(group); 38 39 if (group->ops->free_group_priv) 40 group->ops->free_group_priv(group); 41 42 kfree(group); 43 } 44 45 /* 46 * Trying to get rid of a group. We need to first get rid of any outstanding 47 * allocations and then free the group. Remember that fsnotify_clear_marks_by_group 48 * could miss marks that are being freed by inode and those marks could still 49 * hold a reference to this group (via group->num_marks) If we get into that 50 * situtation, the fsnotify_final_destroy_group will get called when that final 51 * mark is freed. 52 */ 53 static void fsnotify_destroy_group(struct fsnotify_group *group) 54 { 55 /* clear all inode marks for this group */ 56 fsnotify_clear_marks_by_group(group); 57 58 synchronize_srcu(&fsnotify_mark_srcu); 59 60 /* past the point of no return, matches the initial value of 1 */ 61 if (atomic_dec_and_test(&group->num_marks)) 62 fsnotify_final_destroy_group(group); 63 } 64 65 /* 66 * Drop a reference to a group. Free it if it's through. 67 */ 68 void fsnotify_put_group(struct fsnotify_group *group) 69 { 70 if (atomic_dec_and_test(&group->refcnt)) 71 fsnotify_destroy_group(group); 72 } 73 74 /* 75 * Create a new fsnotify_group and hold a reference for the group returned. 76 */ 77 struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) 78 { 79 struct fsnotify_group *group; 80 81 group = kzalloc(sizeof(struct fsnotify_group), GFP_KERNEL); 82 if (!group) 83 return ERR_PTR(-ENOMEM); 84 85 /* set to 0 when there a no external references to this group */ 86 atomic_set(&group->refcnt, 1); 87 /* 88 * hits 0 when there are no external references AND no marks for 89 * this group 90 */ 91 atomic_set(&group->num_marks, 1); 92 93 mutex_init(&group->notification_mutex); 94 INIT_LIST_HEAD(&group->notification_list); 95 init_waitqueue_head(&group->notification_waitq); 96 group->max_events = UINT_MAX; 97 98 spin_lock_init(&group->mark_lock); 99 INIT_LIST_HEAD(&group->marks_list); 100 101 group->ops = ops; 102 103 return group; 104 } 105