]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
kclient: maintain min and max cap hold delays
authorSage Weil <sage@newdream.net>
Wed, 8 Apr 2009 22:17:04 +0000 (15:17 -0700)
committerSage Weil <sage@newdream.net>
Wed, 8 Apr 2009 22:17:04 +0000 (15:17 -0700)
Set a minimum amount of time we keep caps wanted bits even after
the file is closed.  Before that time, even if we are sending a
cap message, we tell the mds we still want the caps.  After the min
but before the max, we will tell the mds we no longer need them
IF we are sending a cap message for some other reason.

The caps_delay queue works as before based on the max timeout. When
that timer goes off, send a new message to release the wanted bits.

In most cases, this now releases wanted bits when we write back the
file size to the mds after writepages, which means only a single
message after we write and close a file.  Yay!

src/kernel/caps.c
src/kernel/inode.c
src/kernel/super.c
src/kernel/super.h

index af41a775ee98e19c26910eff72e3ac5ed44eae08..38af32dab4a95695e61106fc0e30150255ae9fdc 100644 (file)
@@ -343,10 +343,14 @@ static void __insert_cap_node(struct ceph_inode_info *ci,
 static void __cap_delay_requeue(struct ceph_mds_client *mdsc,
                                struct ceph_inode_info *ci)
 {
-       struct ceph_client *client = mdsc->client;
-       ci->i_hold_caps_until = round_jiffies(jiffies + client->mount_args.caps_delay * HZ);
+       struct ceph_mount_args *ma = &mdsc->client->mount_args;
+
+       ci->i_hold_caps_min = round_jiffies(jiffies +
+                                           ma->caps_wanted_delay_min * HZ);
+       ci->i_hold_caps_max = round_jiffies(jiffies +
+                                           ma->caps_wanted_delay_max * HZ);
        dout(10, "__cap_delay_requeue %p at %lu\n", &ci->vfs_inode,
-            ci->i_hold_caps_until);
+            ci->i_hold_caps_max);
        if (!mdsc->stopping) {
                spin_lock(&mdsc->cap_delay_lock);
                if (!list_empty(&ci->i_cap_delay_list))
@@ -1034,7 +1038,7 @@ retry_locked:
         * have cached pages, but don't want them, then try to invalidate.
         * If we fail, it's because pages are locked.... try again later.
         */
-       if ((!time_before(jiffies, ci->i_hold_caps_until) || mdsc->stopping) &&
+       if ((!time_before(jiffies, ci->i_hold_caps_max) || mdsc->stopping) &&
            ci->i_wrbuffer_ref == 0 &&               /* no dirty pages... */
            ci->i_rdcache_gen &&                     /* may have cached pages */
            file_wanted == 0 &&                      /* no open files */
@@ -1112,7 +1116,7 @@ retry_locked:
 
                /* delay cap release for a bit? */
                if (!is_delayed &&
-                   time_before(jiffies, ci->i_hold_caps_until)) {
+                   time_before(jiffies, ci->i_hold_caps_max)) {
                        dout(30, "delaying cap release\n");
                        continue;
                }
@@ -1228,6 +1232,7 @@ retry:
        if (ci->i_dirty_caps && ci->i_auth_cap) {
                struct ceph_cap *cap = ci->i_auth_cap;
                int used = __ceph_caps_used(ci);
+               int want = __ceph_caps_wanted(ci);
 
                if (!session) {
                        spin_unlock(&inode->i_lock);
@@ -1249,8 +1254,14 @@ retry:
                ci->i_flushing_caps |= flushing;
                ci->i_dirty_caps = 0;
 
+               /* don't release wanted unless we've waited a bit. */
+               if (time_before(jiffies, ci->i_hold_caps_min))
+                       want = cap->mds_wanted;
+               else if (!want)
+                       __cap_delay_cancel(mdsc, ci);
+
                /* __send_cap drops i_lock */
-               __send_cap(mdsc, cap, CEPH_CAP_OP_UPDATE, used, cap->mds_wanted,
+               __send_cap(mdsc, cap, CEPH_CAP_OP_UPDATE, used, want,
                           cap->issued | cap->implemented, flushing);
                goto out_unlocked;
        }
@@ -2111,7 +2122,7 @@ void ceph_check_delayed_caps(struct ceph_mds_client *mdsc)
                ci = list_first_entry(&mdsc->cap_delay_list,
                                      struct ceph_inode_info,
                                      i_cap_delay_list);
-               if (time_before(jiffies, ci->i_hold_caps_until))
+               if (time_before(jiffies, ci->i_hold_caps_max))
                        break;
                list_del_init(&ci->i_cap_delay_list);
                spin_unlock(&mdsc->cap_delay_lock);
index ea415d423d6707d2bea25dd92d4a57cc1209a6a3..1c7c49b3c39bd4a2f8f69e4197ec5ce6f341c0b1 100644 (file)
@@ -265,7 +265,8 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        INIT_LIST_HEAD(&ci->i_dirty_item);
        INIT_LIST_HEAD(&ci->i_sync_item);
        init_waitqueue_head(&ci->i_cap_wq);
-       ci->i_hold_caps_until = 0;
+       ci->i_hold_caps_min = 0;
+       ci->i_hold_caps_max = 0;
        INIT_LIST_HEAD(&ci->i_cap_delay_list);
        ci->i_cap_exporting_mds = 0;
        ci->i_cap_exporting_mseq = 0;
index f21f2c63270c914476659adbf5223eef3a4b624d..4660cb30e5bd5b6b5e970fa9b44c8e22ecd11ce4 100644 (file)
@@ -374,7 +374,8 @@ enum {
        Opt_rsize,
        Opt_osdtimeout,
        Opt_mount_timeout,
-       Opt_caps_delay,
+       Opt_caps_wanted_delay_min,
+       Opt_caps_wanted_delay_max,
        /* int args above */
        Opt_ip,
        Opt_noshare,
@@ -405,7 +406,8 @@ static match_table_t arg_tokens = {
        {Opt_rsize, "rsize=%d"},
        {Opt_osdtimeout, "osdtimeout=%d"},
        {Opt_mount_timeout, "mount_timeout=%d"},
-       {Opt_caps_delay, "caps_delay=%d"},
+       {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"},
+       {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"},
        /* int args above */
        {Opt_ip, "ip=%s"},
        {Opt_debug_console, "debug_console"},
@@ -510,7 +512,8 @@ static int parse_mount_args(int flags, char *options, const char *dev_name,
        args->flags = CEPH_MOUNT_DEFAULT;
        args->osd_timeout = 5;    /* seconds */
        args->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */
-       args->caps_delay = CEPH_CAP_DELAY_DEFAULT; /* seconds */
+       args->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
+       args->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
        args->snapdir_name = ".snap";
        args->cap_release_safety = CAPS_PER_RELEASE * 4;
 
@@ -627,8 +630,11 @@ static int parse_mount_args(int flags, char *options, const char *dev_name,
                case Opt_mount_timeout:
                        args->mount_timeout = intval;
                        break;
-               case Opt_caps_delay:
-                       args->caps_delay = intval;
+               case Opt_caps_wanted_delay_min:
+                       args->caps_wanted_delay_min = intval;
+                       break;
+               case Opt_caps_wanted_delay_max:
+                       args->caps_wanted_delay_max = intval;
                        break;
 
                case Opt_noshare:
index f2345927428ea28eaedb8c4e37140547f13cca8c..ed67f91ba8df6022fc0137b0ab8541d989a55de3 100644 (file)
 #define CEPH_BLOCK         (1 << CEPH_BLOCK_SHIFT)
 
 #define CEPH_MOUNT_TIMEOUT_DEFAULT  60
-#define CEPH_CAP_DELAY_DEFAULT      60  /* cap release delay */
+
+/*
+ * Delay telling the MDS we no longer wnat caps, in case we reopen
+ * the file.  Delay a minimum amount of time, even if we send a cap
+ * message for some other reason.  Otherwise, take the oppotunity to
+ * update the mds to avoid sending another message later.
+ */
+#define CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT      5  /* cap release delay */
+#define CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT     60  /* cap release delay */
 
 /*
  * subtract jiffies
@@ -59,7 +67,7 @@ struct ceph_mount_args {
        int sb_flags;
        int flags;
        int mount_timeout;
-       int caps_delay;
+       int caps_wanted_delay_min, caps_wanted_delay_max;
        ceph_fsid_t fsid;
        struct ceph_entity_addr my_addr;
        int num_mon;
@@ -261,7 +269,8 @@ struct ceph_inode_info {
        unsigned i_dirty_caps, i_flushing_caps;     /* mask of dirtied fields */
        struct list_head i_dirty_item, i_sync_item;
        wait_queue_head_t i_cap_wq;      /* threads waiting on a capability */
-       unsigned long i_hold_caps_until; /* jiffies */
+       unsigned long i_hold_caps_min; /* jiffies */
+       unsigned long i_hold_caps_max; /* jiffies */
        struct list_head i_cap_delay_list;  /* for delayed cap release to mds */
        int i_cap_exporting_mds;         /* to handle cap migration between */
        unsigned i_cap_exporting_mseq;   /*  mds's. */