diff options
Diffstat (limited to 'fs/notify/inotify/inotify_fsnotify.c')
| -rw-r--r-- | fs/notify/inotify/inotify_fsnotify.c | 161 | 
1 files changed, 60 insertions, 101 deletions
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 4216308b81b..43ab1e1a07a 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c @@ -34,107 +34,90 @@  #include "inotify.h"  /* - * Check if 2 events contain the same information.  We do not compare private data - * but at this moment that isn't a problem for any know fsnotify listeners. + * Check if 2 events contain the same information.   */ -static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new) +static bool event_compare(struct fsnotify_event *old_fsn, +			  struct fsnotify_event *new_fsn)  { -	if ((old->mask == new->mask) && -	    (old->to_tell == new->to_tell) && -	    (old->data_type == new->data_type) && -	    (old->name_len == new->name_len)) { -		switch (old->data_type) { -		case (FSNOTIFY_EVENT_INODE): -			/* remember, after old was put on the wait_q we aren't -			 * allowed to look at the inode any more, only thing -			 * left to check was if the file_name is the same */ -			if (!old->name_len || -			    !strcmp(old->file_name, new->file_name)) -				return true; -			break; -		case (FSNOTIFY_EVENT_PATH): -			if ((old->path.mnt == new->path.mnt) && -			    (old->path.dentry == new->path.dentry)) -				return true; -			break; -		case (FSNOTIFY_EVENT_NONE): -			if (old->mask & FS_Q_OVERFLOW) -				return true; -			else if (old->mask & FS_IN_IGNORED) -				return false; -			return true; -		}; -	} +	struct inotify_event_info *old, *new; + +	if (old_fsn->mask & FS_IN_IGNORED) +		return false; +	old = INOTIFY_E(old_fsn); +	new = INOTIFY_E(new_fsn); +	if ((old_fsn->mask == new_fsn->mask) && +	    (old_fsn->inode == new_fsn->inode) && +	    (old->name_len == new->name_len) && +	    (!old->name_len || !strcmp(old->name, new->name))) +		return true;  	return false;  } -static struct fsnotify_event *inotify_merge(struct list_head *list, -					    struct fsnotify_event *event) +static int inotify_merge(struct list_head *list, +			  struct fsnotify_event *event)  { -	struct fsnotify_event_holder *last_holder;  	struct fsnotify_event *last_event; -	/* and the list better be locked by something too */ -	spin_lock(&event->lock); - -	last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list); -	last_event = last_holder->event; -	if (event_compare(last_event, event)) -		fsnotify_get_event(last_event); -	else -		last_event = NULL; - -	spin_unlock(&event->lock); - -	return last_event; +	last_event = list_entry(list->prev, struct fsnotify_event, list); +	return event_compare(last_event, event);  } -static int inotify_handle_event(struct fsnotify_group *group, -				struct fsnotify_mark *inode_mark, -				struct fsnotify_mark *vfsmount_mark, -				struct fsnotify_event *event) +int inotify_handle_event(struct fsnotify_group *group, +			 struct inode *inode, +			 struct fsnotify_mark *inode_mark, +			 struct fsnotify_mark *vfsmount_mark, +			 u32 mask, void *data, int data_type, +			 const unsigned char *file_name, u32 cookie)  {  	struct inotify_inode_mark *i_mark; -	struct inode *to_tell; -	struct inotify_event_private_data *event_priv; -	struct fsnotify_event_private_data *fsn_event_priv; -	struct fsnotify_event *added_event; -	int wd, ret = 0; +	struct inotify_event_info *event; +	struct fsnotify_event *fsn_event; +	int ret; +	int len = 0; +	int alloc_len = sizeof(struct inotify_event_info);  	BUG_ON(vfsmount_mark); -	pr_debug("%s: group=%p event=%p to_tell=%p mask=%x\n", __func__, group, -		 event, event->to_tell, event->mask); +	if ((inode_mark->mask & FS_EXCL_UNLINK) && +	    (data_type == FSNOTIFY_EVENT_PATH)) { +		struct path *path = data; + +		if (d_unlinked(path->dentry)) +			return 0; +	} +	if (file_name) { +		len = strlen(file_name); +		alloc_len += len + 1; +	} -	to_tell = event->to_tell; +	pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode, +		 mask);  	i_mark = container_of(inode_mark, struct inotify_inode_mark,  			      fsn_mark); -	wd = i_mark->wd; -	event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL); -	if (unlikely(!event_priv)) +	event = kmalloc(alloc_len, GFP_KERNEL); +	if (unlikely(!event))  		return -ENOMEM; -	fsn_event_priv = &event_priv->fsnotify_event_priv_data; - -	fsnotify_get_group(group); -	fsn_event_priv->group = group; -	event_priv->wd = wd; - -	added_event = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge); -	if (added_event) { -		inotify_free_event_priv(fsn_event_priv); -		if (!IS_ERR(added_event)) -			fsnotify_put_event(added_event); -		else -			ret = PTR_ERR(added_event); +	fsn_event = &event->fse; +	fsnotify_init_event(fsn_event, inode, mask); +	event->wd = i_mark->wd; +	event->sync_cookie = cookie; +	event->name_len = len; +	if (len) +		strcpy(event->name, file_name); + +	ret = fsnotify_add_notify_event(group, fsn_event, inotify_merge); +	if (ret) { +		/* Our event wasn't used in the end. Free it. */ +		fsnotify_destroy_event(group, fsn_event);  	}  	if (inode_mark->mask & IN_ONESHOT)  		fsnotify_destroy_mark(inode_mark, group); -	return ret; +	return 0;  }  static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify_group *group) @@ -142,22 +125,6 @@ static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify  	inotify_ignored_and_remove_idr(fsn_mark, group);  } -static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, -				      struct fsnotify_mark *inode_mark, -				      struct fsnotify_mark *vfsmount_mark, -				      __u32 mask, void *data, int data_type) -{ -	if ((inode_mark->mask & FS_EXCL_UNLINK) && -	    (data_type == FSNOTIFY_EVENT_PATH)) { -		struct path *path = data; - -		if (d_unlinked(path->dentry)) -			return false; -	} - -	return true; -} -  /*   * This is NEVER supposed to be called.  Inotify marks should either have been   * removed from the idr when the watch was removed or in the @@ -202,22 +169,14 @@ static void inotify_free_group_priv(struct fsnotify_group *group)  	free_uid(group->inotify_data.user);  } -void inotify_free_event_priv(struct fsnotify_event_private_data *fsn_event_priv) +static void inotify_free_event(struct fsnotify_event *fsn_event)  { -	struct inotify_event_private_data *event_priv; - - -	event_priv = container_of(fsn_event_priv, struct inotify_event_private_data, -				  fsnotify_event_priv_data); - -	fsnotify_put_group(fsn_event_priv->group); -	kmem_cache_free(event_priv_cachep, event_priv); +	kfree(INOTIFY_E(fsn_event));  }  const struct fsnotify_ops inotify_fsnotify_ops = {  	.handle_event = inotify_handle_event, -	.should_send_event = inotify_should_send_event,  	.free_group_priv = inotify_free_group_priv, -	.free_event_priv = inotify_free_event_priv, +	.free_event = inotify_free_event,  	.freeing_mark = inotify_freeing_mark,  };  | 
