From ef29431985e25f01eb4c8a4e7d8eedd2a25ac49f Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Tue, 31 Mar 2009 14:44:42 -0700 Subject: [PATCH] kclient: add dentry lru --- src/kernel/debugfs.c | 30 +++++++++++++++++++++ src/kernel/dir.c | 58 +++++++++++++++++++++++++++++++++++++---- src/kernel/inode.c | 51 +++++++++++++++++++++++++----------- src/kernel/mds_client.c | 3 +++ src/kernel/mds_client.h | 4 +++ src/kernel/super.h | 8 +++++- 6 files changed, 133 insertions(+), 21 deletions(-) diff --git a/src/kernel/debugfs.c b/src/kernel/debugfs.c index de664447cc6c5..5f81108113101 100644 --- a/src/kernel/debugfs.c +++ b/src/kernel/debugfs.c @@ -367,6 +367,26 @@ static int osdc_show(struct seq_file *s, void *p) return 0; } +static int dentry_lru_show(struct seq_file *s, void *ptr) +{ + struct ceph_client *client = s->private; + struct ceph_mds_client *mdsc = &client->mdsc; + struct list_head *p; + struct ceph_dentry_info *di; + + spin_lock(&mdsc->dentry_lru_lock); + list_for_each(p, &mdsc->dentry_lru) { + struct dentry *dentry; + di = list_entry(p, struct ceph_dentry_info, lru); + dentry = di->dentry; + seq_printf(s, "%p %p\t%.*s\n", + di, dentry, dentry->d_name.len, dentry->d_name.name); + } + spin_unlock(&mdsc->dentry_lru_lock); + + return 0; +} + #define DEFINE_SHOW_FUNC(name) \ static int name##_open(struct inode *inode, struct file *file) \ { \ @@ -393,6 +413,7 @@ DEFINE_SHOW_FUNC(osdmap_show) DEFINE_SHOW_FUNC(monc_show) DEFINE_SHOW_FUNC(mdsc_show) DEFINE_SHOW_FUNC(osdc_show) +DEFINE_SHOW_FUNC(dentry_lru_show) #ifdef CONFIG_CEPH_BOOKKEEPER static int debugfs_bookkeeper_set(void *data, u64 val) @@ -545,6 +566,14 @@ int ceph_debugfs_client_init(struct ceph_client *client) if (!client->debugfs_osdmap) goto out; + client->debugfs_dentry_lru = debugfs_create_file("dentry_lru", + 0600, + client->debugfs_dir, + client, + &dentry_lru_show_fops); + if (!client->debugfs_osdmap) + goto out; + return 0; out: @@ -557,6 +586,7 @@ void ceph_debugfs_client_cleanup(struct ceph_client *client) debugfs_remove(client->monc.debugfs_file); debugfs_remove(client->mdsc.debugfs_file); debugfs_remove(client->osdc.debugfs_file); + debugfs_remove(client->debugfs_dentry_lru); debugfs_remove(client->debugfs_monmap); debugfs_remove(client->debugfs_mdsmap); debugfs_remove(client->debugfs_osdmap); diff --git a/src/kernel/dir.c b/src/kernel/dir.c index c6d29f5e92a4a..d70564b8fbfdb 100644 --- a/src/kernel/dir.c +++ b/src/kernel/dir.c @@ -617,7 +617,7 @@ static int dentry_lease_is_valid(struct dentry *dentry) spin_lock(&dentry->d_lock); di = ceph_dentry(dentry); - if (di) { + if (di && di->lease_session) { s = di->lease_session; spin_lock(&s->s_cap_lock); gen = s->s_cap_gen; @@ -683,20 +683,23 @@ static int ceph_dentry_revalidate(struct dentry *dentry, struct nameidata *nd) if (ceph_snap(dir) != CEPH_NOSNAP) { dout(10, "d_revalidate %p '%.*s' inode %p is SNAPPED\n", dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); - return 1; + goto out_touch; } if (dentry_lease_is_valid(dentry)) - return 1; + goto out_touch; if (dir_lease_is_valid(dir, dentry)) - return 1; + goto out_touch; dout(20, "dentry_revalidate %p invalid, clearing %p complete\n", dentry, dir); ceph_i_clear(dir, CEPH_I_COMPLETE|CEPH_I_READDIR); d_drop(dentry); return 0; +out_touch: + ceph_dentry_lru_touch(dentry); + return 1; } static void ceph_dentry_release(struct dentry *dentry) @@ -705,7 +708,9 @@ static void ceph_dentry_release(struct dentry *dentry) struct inode *parent_inode = dentry->d_parent->d_inode; if (di) { - ceph_put_mds_session(di->lease_session); + ceph_dentry_lru_del(dentry); + if (di->lease_session) + ceph_put_mds_session(di->lease_session); kfree(di); dentry->d_fsdata = NULL; } @@ -824,6 +829,49 @@ out: return ret; } +void ceph_dentry_lru_add(struct dentry *dn) +{ + struct ceph_dentry_info *di = ceph_dentry(dn); + struct ceph_mds_client *mdsc; + dout(30, "dentry_lru_add %p %p\t%.*s\n", + di, dn, dn->d_name.len, dn->d_name.name); + + if (di) { + mdsc = &ceph_client(dn->d_sb)->mdsc; + spin_lock(&mdsc->dentry_lru_lock); + list_add_tail(&di->lru, &mdsc->dentry_lru); + mdsc->num_dentry++; + spin_unlock(&mdsc->dentry_lru_lock); + } +} + +void ceph_dentry_lru_touch(struct dentry *dn) +{ + struct ceph_dentry_info *di = ceph_dentry(dn); + struct ceph_mds_client *mdsc; + + if (di) { + mdsc = &ceph_client(dn->d_sb)->mdsc; + spin_lock(&mdsc->dentry_lru_lock); + list_move_tail(&di->lru, &mdsc->dentry_lru); + spin_unlock(&mdsc->dentry_lru_lock); + } +} + +void ceph_dentry_lru_del(struct dentry *dn) +{ + struct ceph_dentry_info *di = ceph_dentry(dn); + struct ceph_mds_client *mdsc; + + if (di) { + mdsc = &ceph_client(dn->d_sb)->mdsc; + spin_lock(&mdsc->dentry_lru_lock); + list_del_init(&di->lru); + mdsc->num_dentry--; + spin_unlock(&mdsc->dentry_lru_lock); + } +} + const struct file_operations ceph_dir_fops = { .read = ceph_read_dir, .readdir = ceph_readdir, diff --git a/src/kernel/inode.c b/src/kernel/inode.c index ce5e770840b19..1eba5000a2542 100644 --- a/src/kernel/inode.c +++ b/src/kernel/inode.c @@ -647,6 +647,32 @@ out: return err; } +static int __init_ceph_dentry(struct dentry *dentry, int locked) +{ + struct ceph_dentry_info *di; + + if (locked) + spin_unlock(&dentry->d_lock); + di = kmalloc(sizeof(struct ceph_dentry_info), + GFP_NOFS); + + if (locked) + spin_lock(&dentry->d_lock); + if (!di) + return -ENOMEM; /* oh well */ + + if (dentry->d_fsdata) { + kfree(di); /* lost a race! */ + return 0; + } + dentry->d_fsdata = di; + di->dentry = dentry; + di->lease_session = NULL; + ceph_dentry_lru_add(dentry); + + return 0; +} + /* * caller should hold session s_mutex. */ @@ -656,7 +682,6 @@ static void update_dentry_lease(struct dentry *dentry, unsigned long from_time) { struct ceph_dentry_info *di; - int is_new = 0; long unsigned duration = le32_to_cpu(lease->duration_ms); long unsigned ttl = from_time + (duration * HZ) / 1000; long unsigned half_ttl = from_time + (duration * HZ / 2) / 1000; @@ -688,23 +713,18 @@ static void update_dentry_lease(struct dentry *dentry, goto out_unlock; /* we already have a newer lease. */ if (!di) { - spin_unlock(&dentry->d_lock); - di = kmalloc(sizeof(struct ceph_dentry_info), - GFP_NOFS); + __init_ceph_dentry(dentry, 1); + di = ceph_dentry(dentry); if (!di) - return; /* oh well */ - spin_lock(&dentry->d_lock); - if (dentry->d_fsdata) { - kfree(di); /* lost a race! */ goto out_unlock; - } - dentry->d_fsdata = di; - di->lease_session = ceph_get_mds_session(session); - di->lease_gen = session->s_cap_gen; - di->lease_seq = le32_to_cpu(lease->seq); - is_new = 1; - } else if (di->lease_session != session) + } else if (di->lease_session != session) { goto out_unlock; + } else { + ceph_dentry_lru_touch(dentry); + } + di->lease_session = ceph_get_mds_session(session); + di->lease_gen = session->s_cap_gen; + di->lease_seq = le32_to_cpu(lease->seq); di->lease_renew_after = half_ttl; di->lease_renew_from = 0; dentry->d_time = ttl; @@ -746,6 +766,7 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, dput(dn); dn = realdn; ceph_init_dentry(dn); + __init_ceph_dentry(dn, 0); } else { dout(10, "dn %p attached to %p ino %llx.%llx\n", dn, dn->d_inode, ceph_vinop(dn->d_inode)); diff --git a/src/kernel/mds_client.c b/src/kernel/mds_client.c index 7ac8eb7455a99..e37ee62937674 100644 --- a/src/kernel/mds_client.c +++ b/src/kernel/mds_client.c @@ -1880,6 +1880,7 @@ void __ceph_mdsc_drop_dentry_lease(struct dentry *dentry) struct ceph_dentry_info *di = ceph_dentry(dentry); ceph_put_mds_session(di->lease_session); + ceph_dentry_lru_del(dentry); kfree(di); dentry->d_fsdata = NULL; } @@ -2172,6 +2173,8 @@ void ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client) spin_lock_init(&mdsc->cap_delay_lock); INIT_LIST_HEAD(&mdsc->snap_flush_list); spin_lock_init(&mdsc->snap_flush_lock); + spin_lock_init(&mdsc->dentry_lru_lock); + INIT_LIST_HEAD(&mdsc->dentry_lru); } /* diff --git a/src/kernel/mds_client.h b/src/kernel/mds_client.h index 5104b907de11e..811607e7db5d1 100644 --- a/src/kernel/mds_client.h +++ b/src/kernel/mds_client.h @@ -238,6 +238,10 @@ struct ceph_mds_client { spinlock_t snap_flush_lock; struct dentry *debugfs_file; + + spinlock_t dentry_lru_lock; + struct list_head dentry_lru; + int num_dentry; }; extern const char *ceph_mds_op_name(int op); diff --git a/src/kernel/super.h b/src/kernel/super.h index d076203f1c32e..5c95cca0ec98a 100644 --- a/src/kernel/super.h +++ b/src/kernel/super.h @@ -98,7 +98,7 @@ struct ceph_client { struct ceph_client_attr k_fsid, k_monmap, k_mdsmap, k_osdmap; struct dentry *debugfs_fsid, *debugfs_monmap; struct dentry *debugfs_mdsmap, *debugfs_osdmap; - struct dentry *debugfs_dir; + struct dentry *debugfs_dir, *debugfs_dentry_lru; struct mutex mount_mutex; /* serialize mount attempts */ struct ceph_mount_args mount_args; @@ -376,6 +376,8 @@ struct ceph_dentry_info { u32 lease_gen; u32 lease_seq; unsigned long lease_renew_after, lease_renew_from; + struct list_head lru; + struct dentry *dentry; }; static inline struct ceph_dentry_info *ceph_dentry(struct dentry *dentry) @@ -784,6 +786,10 @@ extern struct dentry_operations ceph_dentry_ops, ceph_snap_dentry_ops, extern struct dentry *ceph_finish_lookup(struct ceph_mds_request *req, struct dentry *dentry, int err); +extern void ceph_dentry_lru_add(struct dentry *dn); +extern void ceph_dentry_lru_touch(struct dentry *dn); +extern void ceph_dentry_lru_del(struct dentry *dn); + /* * our d_ops vary depending on whether the inode is live, * snapshotted (read-only), or a virtual ".snap" directory. -- 2.39.5