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