706 lines · 17.5 KB · C
RawDownload
int add_watch_to_object(struct watch *watch, struct watch_list *wlist){	struct watch_queue *wqueue;	int ret = -ENOENT; 	rcu_read_lock(); 	wqueue = rcu_access_pointer(watch->queue);	if (lock_wqueue(wqueue)) {		spin_lock(&wlist->lock);		ret = add_one_watch(watch, wlist, wqueue);		spin_unlock(&wlist->lock);		unlock_wqueue(wqueue);	} 	rcu_read_unlock();	return ret;}EXPORT_SYMBOL(add_watch_to_object); /** * remove_watch_from_object - Remove a watch or all watches from an object. * @wlist: The watch list to remove from * @wq: The watch queue of interest (ignored if @all is true) * @id: The ID of the watch to remove (ignored if @all is true) * @all: True to remove all objects * * Remove a specific watch or all watches from an object.  A notification is * sent to the watcher to tell them that this happened. */int remove_watch_from_object(struct watch_list *wlist, struct watch_queue *wq,			     u64 id, bool all){	struct watch_notification_removal n;	struct watch_queue *wqueue;	struct watch *watch;	int ret = -EBADSLT; 	rcu_read_lock(); again:	spin_lock(&wlist->lock);	hlist_for_each_entry(watch, &wlist->watchers, list_node) {		if (all ||		    (watch->id == id && rcu_access_pointer(watch->queue) == wq))			goto found;	}	spin_unlock(&wlist->lock);	goto out; found:	ret = 0;	hlist_del_init_rcu(&watch->list_node);	rcu_assign_pointer(watch->watch_list, NULL);	spin_unlock(&wlist->lock); 	/* We now own the reference on watch that used to belong to wlist. */ 	n.watch.type = WATCH_TYPE_META;	n.watch.subtype = WATCH_META_REMOVAL_NOTIFICATION;	n.watch.info = watch->info_id | watch_sizeof(n.watch);	n.id = id;	if (id != 0)		n.watch.info = watch->info_id | watch_sizeof(n); 	wqueue = rcu_dereference(watch->queue); 	if (lock_wqueue(wqueue)) {		post_one_notification(wqueue, &n.watch); 		if (!hlist_unhashed(&watch->queue_node)) {			hlist_del_init_rcu(&watch->queue_node);			put_watch(watch);		} 		unlock_wqueue(wqueue);	} 	if (wlist->release_watch) {		void (*release_watch)(struct watch *); 		release_watch = wlist->release_watch;		rcu_read_unlock();		(*release_watch)(watch);		rcu_read_lock();	}	put_watch(watch); 	if (all && !hlist_empty(&wlist->watchers))		goto again;out:	rcu_read_unlock();	return ret;}EXPORT_SYMBOL(remove_watch_from_object); /* * Remove all the watches that are contributory to a queue.  This has the * potential to race with removal of the watches by the destruction of the * objects being watched or with the distribution of notifications. */void watch_queue_clear(struct watch_queue *wqueue){	struct watch_list *wlist;	struct watch *watch;	bool release; 	rcu_read_lock();	spin_lock_bh(&wqueue->lock); 	/*	 * This pipe can be freed by callers like free_pipe_info().	 * Removing this reference also prevents new notifications.	 */	wqueue->pipe = NULL; 	while (!hlist_empty(&wqueue->watches)) {		watch = hlist_entry(wqueue->watches.first, struct watch, queue_node);		hlist_del_init_rcu(&watch->queue_node);		/* We now own a ref on the watch. */		spin_unlock_bh(&wqueue->lock); 		/* We can't do the next bit under the queue lock as we need to		 * get the list lock - which would cause a deadlock if someone		 * was removing from the opposite direction at the same time or		 * posting a notification.		 */		wlist = rcu_dereference(watch->watch_list);		if (wlist) {			void (*release_watch)(struct watch *); 			spin_lock(&wlist->lock); 			release = !hlist_unhashed(&watch->list_node);			if (release) {				hlist_del_init_rcu(&watch->list_node);				rcu_assign_pointer(watch->watch_list, NULL); 				/* We now own a second ref on the watch. */			} 			release_watch = wlist->release_watch;			spin_unlock(&wlist->lock); 			if (release) {				if (release_watch) {					rcu_read_unlock();					/* This might need to call dput(), so					 * we have to drop all the locks.					 */					(*release_watch)(watch);					rcu_read_lock();				}				put_watch(watch);			}		} 		put_watch(watch);		spin_lock_bh(&wqueue->lock);	} 	spin_unlock_bh(&wqueue->lock);	rcu_read_unlock();} /** * get_watch_queue - Get a watch queue from its file descriptor. * @fd: The fd to query. */struct watch_queue *get_watch_queue(int fd){	struct pipe_inode_info *pipe;	struct watch_queue *wqueue = ERR_PTR(-EINVAL);	CLASS(fd, f)(fd); 	if (!fd_empty(f)) {		pipe = get_pipe_info(fd_file(f), false);		if (pipe && pipe->watch_queue) {			wqueue = pipe->watch_queue;			kref_get(&wqueue->usage);		}	} 	return wqueue;}EXPORT_SYMBOL(get_watch_queue); /* * Initialise a watch queue */int watch_queue_init(struct pipe_inode_info *pipe){	struct watch_queue *wqueue; 	wqueue = kzalloc_obj(*wqueue);	if (!wqueue)		return -ENOMEM; 	wqueue->pipe = pipe;	kref_init(&wqueue->usage);	spin_lock_init(&wqueue->lock);	INIT_HLIST_HEAD(&wqueue->watches); 	pipe->watch_queue = wqueue;	return 0;}

Lines 501–706 of 706. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t