| 1 | // SPDX-License-Identifier: GPL-2.0 | 
|---|
| 2 | /* User-mappable watch queue | 
|---|
| 3 | * | 
|---|
| 4 | * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. | 
|---|
| 5 | * Written by David Howells (dhowells@redhat.com) | 
|---|
| 6 | * | 
|---|
| 7 | * See Documentation/core-api/watch_queue.rst | 
|---|
| 8 | */ | 
|---|
| 9 |  | 
|---|
| 10 | #ifndef _LINUX_WATCH_QUEUE_H | 
|---|
| 11 | #define _LINUX_WATCH_QUEUE_H | 
|---|
| 12 |  | 
|---|
| 13 | #include <uapi/linux/watch_queue.h> | 
|---|
| 14 | #include <linux/kref.h> | 
|---|
| 15 | #include <linux/rcupdate.h> | 
|---|
| 16 |  | 
|---|
| 17 | #ifdef CONFIG_WATCH_QUEUE | 
|---|
| 18 |  | 
|---|
| 19 | struct cred; | 
|---|
| 20 |  | 
|---|
| 21 | struct watch_type_filter { | 
|---|
| 22 | enum watch_notification_type type; | 
|---|
| 23 | __u32		subtype_filter[1];	/* Bitmask of subtypes to filter on */ | 
|---|
| 24 | __u32		info_filter;		/* Filter on watch_notification::info */ | 
|---|
| 25 | __u32		info_mask;		/* Mask of relevant bits in info_filter */ | 
|---|
| 26 | }; | 
|---|
| 27 |  | 
|---|
| 28 | struct watch_filter { | 
|---|
| 29 | union { | 
|---|
| 30 | struct rcu_head	rcu; | 
|---|
| 31 | /* Bitmask of accepted types */ | 
|---|
| 32 | DECLARE_BITMAP(type_filter, WATCH_TYPE__NR); | 
|---|
| 33 | }; | 
|---|
| 34 | u32			nr_filters;	/* Number of filters */ | 
|---|
| 35 | struct watch_type_filter filters[] __counted_by(nr_filters); | 
|---|
| 36 | }; | 
|---|
| 37 |  | 
|---|
| 38 | struct watch_queue { | 
|---|
| 39 | struct rcu_head		rcu; | 
|---|
| 40 | struct watch_filter __rcu *filter; | 
|---|
| 41 | struct pipe_inode_info	*pipe;		/* Pipe we use as a buffer, NULL if queue closed */ | 
|---|
| 42 | struct hlist_head	watches;	/* Contributory watches */ | 
|---|
| 43 | struct page		**notes;	/* Preallocated notifications */ | 
|---|
| 44 | unsigned long		*notes_bitmap;	/* Allocation bitmap for notes */ | 
|---|
| 45 | struct kref		usage;		/* Object usage count */ | 
|---|
| 46 | spinlock_t		lock; | 
|---|
| 47 | unsigned int		nr_notes;	/* Number of notes */ | 
|---|
| 48 | unsigned int		nr_pages;	/* Number of pages in notes[] */ | 
|---|
| 49 | }; | 
|---|
| 50 |  | 
|---|
| 51 | /* | 
|---|
| 52 | * Representation of a watch on an object. | 
|---|
| 53 | */ | 
|---|
| 54 | struct watch { | 
|---|
| 55 | union { | 
|---|
| 56 | struct rcu_head	rcu; | 
|---|
| 57 | u32		info_id;	/* ID to be OR'd in to info field */ | 
|---|
| 58 | }; | 
|---|
| 59 | struct watch_queue __rcu *queue;	/* Queue to post events to */ | 
|---|
| 60 | struct hlist_node	queue_node;	/* Link in queue->watches */ | 
|---|
| 61 | struct watch_list __rcu	*watch_list; | 
|---|
| 62 | struct hlist_node	list_node;	/* Link in watch_list->watchers */ | 
|---|
| 63 | const struct cred	*cred;		/* Creds of the owner of the watch */ | 
|---|
| 64 | void			*private;	/* Private data for the watched object */ | 
|---|
| 65 | u64			id;		/* Internal identifier */ | 
|---|
| 66 | struct kref		usage;		/* Object usage count */ | 
|---|
| 67 | }; | 
|---|
| 68 |  | 
|---|
| 69 | /* | 
|---|
| 70 | * List of watches on an object. | 
|---|
| 71 | */ | 
|---|
| 72 | struct watch_list { | 
|---|
| 73 | struct rcu_head		rcu; | 
|---|
| 74 | struct hlist_head	watchers; | 
|---|
| 75 | void (*release_watch)(struct watch *); | 
|---|
| 76 | spinlock_t		lock; | 
|---|
| 77 | }; | 
|---|
| 78 |  | 
|---|
| 79 | extern void __post_watch_notification(struct watch_list *, | 
|---|
| 80 | struct watch_notification *, | 
|---|
| 81 | const struct cred *, | 
|---|
| 82 | u64); | 
|---|
| 83 | extern struct watch_queue *get_watch_queue(int); | 
|---|
| 84 | extern void put_watch_queue(struct watch_queue *); | 
|---|
| 85 | extern void init_watch(struct watch *, struct watch_queue *); | 
|---|
| 86 | extern int add_watch_to_object(struct watch *, struct watch_list *); | 
|---|
| 87 | extern int remove_watch_from_object(struct watch_list *, struct watch_queue *, u64, bool); | 
|---|
| 88 | extern long watch_queue_set_size(struct pipe_inode_info *, unsigned int); | 
|---|
| 89 | extern long watch_queue_set_filter(struct pipe_inode_info *, | 
|---|
| 90 | struct watch_notification_filter __user *); | 
|---|
| 91 | extern int watch_queue_init(struct pipe_inode_info *); | 
|---|
| 92 | extern void watch_queue_clear(struct watch_queue *); | 
|---|
| 93 |  | 
|---|
| 94 | static inline void init_watch_list(struct watch_list *wlist, | 
|---|
| 95 | void (*release_watch)(struct watch *)) | 
|---|
| 96 | { | 
|---|
| 97 | INIT_HLIST_HEAD(&wlist->watchers); | 
|---|
| 98 | spin_lock_init(&wlist->lock); | 
|---|
| 99 | wlist->release_watch = release_watch; | 
|---|
| 100 | } | 
|---|
| 101 |  | 
|---|
| 102 | static inline void post_watch_notification(struct watch_list *wlist, | 
|---|
| 103 | struct watch_notification *n, | 
|---|
| 104 | const struct cred *cred, | 
|---|
| 105 | u64 id) | 
|---|
| 106 | { | 
|---|
| 107 | if (unlikely(wlist)) | 
|---|
| 108 | __post_watch_notification(wlist, n, cred, id); | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 | static inline void remove_watch_list(struct watch_list *wlist, u64 id) | 
|---|
| 112 | { | 
|---|
| 113 | if (wlist) { | 
|---|
| 114 | remove_watch_from_object(wlist, NULL, id, true); | 
|---|
| 115 | kfree_rcu(wlist, rcu); | 
|---|
| 116 | } | 
|---|
| 117 | } | 
|---|
| 118 |  | 
|---|
| 119 | /** | 
|---|
| 120 | * watch_sizeof - Calculate the information part of the size of a watch record, | 
|---|
| 121 | * given the structure size. | 
|---|
| 122 | */ | 
|---|
| 123 | #define watch_sizeof(STRUCT) (sizeof(STRUCT) << WATCH_INFO_LENGTH__SHIFT) | 
|---|
| 124 |  | 
|---|
| 125 | #else | 
|---|
| 126 | static inline int watch_queue_init(struct pipe_inode_info *pipe) | 
|---|
| 127 | { | 
|---|
| 128 | return -ENOPKG; | 
|---|
| 129 | } | 
|---|
| 130 |  | 
|---|
| 131 | #endif | 
|---|
| 132 |  | 
|---|
| 133 | #endif /* _LINUX_WATCH_QUEUE_H */ | 
|---|
| 134 |  | 
|---|