Linux 6.9-rc1
[linux-2.6-microblaze.git] / kernel / watch_queue.c
index 59ddb00..03b90d7 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
- * See Documentation/watch_queue.rst
+ * See Documentation/core-api/watch_queue.rst
  */
 
 #define pr_fmt(fmt) "watchq: " fmt
@@ -29,7 +29,6 @@
 
 MODULE_DESCRIPTION("Watch queue");
 MODULE_AUTHOR("Red Hat, Inc.");
-MODULE_LICENSE("GPL");
 
 #define WATCH_QUEUE_NOTE_SIZE 128
 #define WATCH_QUEUE_NOTES_PER_PAGE (PAGE_SIZE / WATCH_QUEUE_NOTE_SIZE)
@@ -43,7 +42,7 @@ MODULE_LICENSE("GPL");
 static inline bool lock_wqueue(struct watch_queue *wqueue)
 {
        spin_lock_bh(&wqueue->lock);
-       if (unlikely(wqueue->defunct)) {
+       if (unlikely(!wqueue->pipe)) {
                spin_unlock_bh(&wqueue->lock);
                return false;
        }
@@ -105,9 +104,6 @@ static bool post_one_notification(struct watch_queue *wqueue,
        unsigned int head, tail, mask, note, offset, len;
        bool done = false;
 
-       if (!pipe)
-               return false;
-
        spin_lock_irq(&pipe->rd_wait.lock);
 
        mask = pipe->ring_size - 1;
@@ -273,7 +269,8 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes)
        if (ret < 0)
                goto error;
 
-       pages = kcalloc(sizeof(struct page *), nr_pages, GFP_KERNEL);
+       ret = -ENOMEM;
+       pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
        if (!pages)
                goto error;
 
@@ -334,7 +331,7 @@ long watch_queue_set_filter(struct pipe_inode_info *pipe,
            filter.__reserved != 0)
                return -EINVAL;
 
-       tf = memdup_user(_filter->filters, filter.nr_filters * sizeof(*tf));
+       tf = memdup_array_user(_filter->filters, filter.nr_filters, sizeof(*tf));
        if (IS_ERR(tf))
                return PTR_ERR(tf);
 
@@ -603,8 +600,11 @@ void watch_queue_clear(struct watch_queue *wqueue)
        rcu_read_lock();
        spin_lock_bh(&wqueue->lock);
 
-       /* Prevent new notifications from being stored. */
-       wqueue->defunct = true;
+       /*
+        * 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);