ceph: show tasks waiting on caps in debugfs caps file
authorJeff Layton <jlayton@kernel.org>
Wed, 20 Nov 2019 17:00:59 +0000 (12:00 -0500)
committerIlya Dryomov <idryomov@gmail.com>
Mon, 9 Dec 2019 19:55:10 +0000 (20:55 +0100)
Add some visibility of tasks that are waiting for caps to the "caps"
debugfs file. Display the tgid of the waiting task, inode number, and
the caps the task needs and wants.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/caps.c
fs/ceph/debugfs.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h

index f5a3891..271d828 100644 (file)
@@ -2764,7 +2764,19 @@ int ceph_get_caps(struct file *filp, int need, int want,
                if (ret == -EAGAIN)
                        continue;
                if (!ret) {
+                       struct ceph_mds_client *mdsc = fsc->mdsc;
+                       struct cap_wait cw;
                        DEFINE_WAIT_FUNC(wait, woken_wake_function);
+
+                       cw.ino = inode->i_ino;
+                       cw.tgid = current->tgid;
+                       cw.need = need;
+                       cw.want = want;
+
+                       spin_lock(&mdsc->caps_list_lock);
+                       list_add(&cw.list, &mdsc->cap_wait_list);
+                       spin_unlock(&mdsc->caps_list_lock);
+
                        add_wait_queue(&ci->i_cap_wq, &wait);
 
                        flags |= NON_BLOCKING;
@@ -2778,6 +2790,11 @@ int ceph_get_caps(struct file *filp, int need, int want,
                        }
 
                        remove_wait_queue(&ci->i_cap_wq, &wait);
+
+                       spin_lock(&mdsc->caps_list_lock);
+                       list_del(&cw.list);
+                       spin_unlock(&mdsc->caps_list_lock);
+
                        if (ret == -EAGAIN)
                                continue;
                }
index facb387..c281f32 100644 (file)
@@ -139,6 +139,7 @@ static int caps_show(struct seq_file *s, void *p)
        struct ceph_fs_client *fsc = s->private;
        struct ceph_mds_client *mdsc = fsc->mdsc;
        int total, avail, used, reserved, min, i;
+       struct cap_wait *cw;
 
        ceph_reservation_status(fsc, &total, &avail, &used, &reserved, &min);
        seq_printf(s, "total\t\t%d\n"
@@ -166,6 +167,18 @@ static int caps_show(struct seq_file *s, void *p)
        }
        mutex_unlock(&mdsc->mutex);
 
+       seq_printf(s, "\n\nWaiters:\n--------\n");
+       seq_printf(s, "tgid         ino                need             want\n");
+       seq_printf(s, "-----------------------------------------------------\n");
+
+       spin_lock(&mdsc->caps_list_lock);
+       list_for_each_entry(cw, &mdsc->cap_wait_list, list) {
+               seq_printf(s, "%-13d0x%-17lx%-17s%-17s\n", cw->tgid, cw->ino,
+                               ceph_cap_string(cw->need),
+                               ceph_cap_string(cw->want));
+       }
+       spin_unlock(&mdsc->caps_list_lock);
+
        return 0;
 }
 
index a3110d2..f8735fc 100644 (file)
@@ -4169,6 +4169,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        INIT_DELAYED_WORK(&mdsc->delayed_work, delayed_work);
        mdsc->last_renew_caps = jiffies;
        INIT_LIST_HEAD(&mdsc->cap_delay_list);
+       INIT_LIST_HEAD(&mdsc->cap_wait_list);
        spin_lock_init(&mdsc->cap_delay_lock);
        INIT_LIST_HEAD(&mdsc->snap_flush_list);
        spin_lock_init(&mdsc->snap_flush_lock);
index 5cd131b..14c7e8c 100644 (file)
@@ -340,6 +340,14 @@ struct ceph_quotarealm_inode {
        struct inode *inode;
 };
 
+struct cap_wait {
+       struct list_head        list;
+       unsigned long           ino;
+       pid_t                   tgid;
+       int                     need;
+       int                     want;
+};
+
 /*
  * mds client state
  */
@@ -416,6 +424,7 @@ struct ceph_mds_client {
        spinlock_t      caps_list_lock;
        struct          list_head caps_list; /* unused (reserved or
                                                unreserved) */
+       struct          list_head cap_wait_list;
        int             caps_total_count;    /* total caps allocated */
        int             caps_use_count;      /* in use */
        int             caps_use_max;        /* max used caps */