Whamcloud - gitweb
LU-11288 osc: re-check target versus available grant
[fs/lustre-release.git] / lustre / target / tgt_grant.c
index 7887623..99373cf 100644 (file)
@@ -23,7 +23,7 @@
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2012, 2016, Intel Corporation.
+ * Copyright (c) 2012, 2017, Intel Corporation.
  */
 /*
  * lustre/target/tgt_grant.c
@@ -280,14 +280,14 @@ EXPORT_SYMBOL(tgt_grant_sanity_check);
  * \retval             negative value on error
  */
 int tgt_statfs_internal(const struct lu_env *env, struct lu_target *lut,
-                       struct obd_statfs *osfs, __u64 max_age, int *from_cache)
+                       struct obd_statfs *osfs, time64_t max_age, int *from_cache)
 {
        struct tg_grants_data *tgd = &lut->lut_tgd;
        int rc = 0;
        ENTRY;
 
        spin_lock(&tgd->tgd_osfs_lock);
-       if (cfs_time_before_64(tgd->tgd_osfs_age, max_age) || max_age == 0) {
+       if (tgd->tgd_osfs_age < max_age || max_age == 0) {
                u64 unstable;
 
                /* statfs data are too old, get up-to-date one.
@@ -313,6 +313,8 @@ int tgt_statfs_internal(const struct lu_env *env, struct lu_target *lut,
                if (unlikely(rc))
                        GOTO(out, rc);
 
+               osfs->os_namelen = min_t(__u32, osfs->os_namelen, NAME_MAX);
+
                spin_lock(&tgd->tgd_grant_lock);
                spin_lock(&tgd->tgd_osfs_lock);
                /* calculate how much space was written while we released the
@@ -342,7 +344,7 @@ int tgt_statfs_internal(const struct lu_env *env, struct lu_target *lut,
 
                /* finally udpate cached statfs data */
                tgd->tgd_osfs = *osfs;
-               tgd->tgd_osfs_age = cfs_time_current_64();
+               tgd->tgd_osfs_age = ktime_get_seconds();
 
                tgd->tgd_statfs_inflight--; /* stop tracking */
                if (tgd->tgd_statfs_inflight == 0)
@@ -388,13 +390,13 @@ static void tgt_grant_statfs(const struct lu_env *env, struct obd_export *exp,
        struct tg_grants_data   *tgd = &lut->lut_tgd;
        struct tgt_thread_info  *tti;
        struct obd_statfs       *osfs;
-       __u64                    max_age;
-       int                      rc;
+       time64_t max_age;
+       int rc;
 
        if (force)
                max_age = 0; /* get fresh statfs data */
        else
-               max_age = cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS);
+               max_age = ktime_get_seconds() - OBD_STATFS_CACHE_SECONDS;
 
        tti = tgt_th_info(env);
        osfs = &tti->tti_u.osfs;
@@ -433,6 +435,7 @@ static u64 tgt_grant_space_left(struct obd_export *exp)
        u64                      left;
        u64                      avail;
        u64                      unstable;
+       u64                      reserved;
 
        ENTRY;
        assert_spin_locked(&tgd->tgd_grant_lock);
@@ -443,7 +446,8 @@ static u64 tgt_grant_space_left(struct obd_export *exp)
        unstable = tgd->tgd_osfs_unstable; /* those might be accounted twice */
        spin_unlock(&tgd->tgd_osfs_lock);
 
-       tot_granted = tgd->tgd_tot_granted;
+       reserved = left * tgd->tgd_reserved_pcnt / 100;
+       tot_granted = tgd->tgd_tot_granted + reserved;
 
        if (left < tot_granted) {
                int mask = (left + unstable <
@@ -890,9 +894,10 @@ static long tgt_grant_alloc(struct obd_export *exp, u64 curgrant,
             tgd->tgd_grant_compat_disable) || left == 0 || exp->exp_failed)
                RETURN(0);
 
-       if (want > 0x7fffffff) {
-               CERROR("%s: client %s/%p requesting > 2GB grant %llu\n",
-                      obd->obd_name, exp->exp_client_uuid.uuid, exp, want);
+       if (want > OBD_MAX_GRANT) {
+               CERROR("%s: client %s/%p requesting > max (%lu), %llu\n",
+                      obd->obd_name, exp->exp_client_uuid.uuid, exp,
+                      OBD_MAX_GRANT, want);
                RETURN(0);
        }
 
@@ -927,6 +932,16 @@ static long tgt_grant_alloc(struct obd_export *exp, u64 curgrant,
        if ((grant > chunk) && conservative)
                grant = chunk;
 
+       /*
+        * Limit grant so that export' grant does not exceed what the
+        * client would like to have by more than grants for 2 full
+        * RPCs
+        */
+       if (want + chunk <= ted->ted_grant)
+               RETURN(0);
+       if (ted->ted_grant + grant > want + chunk)
+               grant = want + chunk - ted->ted_grant;
+
        tgd->tgd_tot_granted += grant;
        ted->ted_grant += grant;
 
@@ -1049,9 +1064,14 @@ EXPORT_SYMBOL(tgt_grant_connect);
 void tgt_grant_discard(struct obd_export *exp)
 {
        struct obd_device       *obd = exp->exp_obd;
-       struct tg_grants_data   *tgd = &obd->u.obt.obt_lut->lut_tgd;
+       struct lu_target        *lut = class_exp2tgt(exp);
        struct tg_export_data   *ted = &exp->exp_target_data;
+       struct tg_grants_data   *tgd;
+
+       if (!lut)
+               return;
 
+       tgd = &lut->lut_tgd;
        spin_lock(&tgd->tgd_grant_lock);
        LASSERTF(tgd->tgd_tot_granted >= ted->ted_grant,
                 "%s: tot_granted %llu cli %s/%p ted_grant %ld\n",
@@ -1505,3 +1525,127 @@ int tgt_grant_commit_cb_add(struct thandle *th, struct obd_export *exp,
        RETURN(rc);
 }
 EXPORT_SYMBOL(tgt_grant_commit_cb_add);
+
+/**
+ * Show estimate of total amount of dirty data on clients.
+ *
+ * \param[in] m                seq_file handle
+ * \param[in] data     unused for single entry
+ *
+ * \retval             0 on success
+ * \retval             negative value on error
+ */
+int tgt_tot_dirty_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = m->private;
+       struct tg_grants_data *tgd;
+
+       LASSERT(obd != NULL);
+       tgd = &obd->u.obt.obt_lut->lut_tgd;
+       seq_printf(m, "%llu\n", tgd->tgd_tot_dirty);
+       return 0;
+}
+EXPORT_SYMBOL(tgt_tot_dirty_seq_show);
+
+/**
+ * Show total amount of space granted to clients.
+ *
+ * \param[in] m                seq_file handle
+ * \param[in] data     unused for single entry
+ *
+ * \retval             0 on success
+ * \retval             negative value on error
+ */
+int tgt_tot_granted_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = m->private;
+       struct tg_grants_data *tgd;
+
+       LASSERT(obd != NULL);
+       tgd = &obd->u.obt.obt_lut->lut_tgd;
+       seq_printf(m, "%llu\n", tgd->tgd_tot_granted);
+       return 0;
+}
+EXPORT_SYMBOL(tgt_tot_granted_seq_show);
+
+/**
+ * Show total amount of space used by IO in progress.
+ *
+ * \param[in] m                seq_file handle
+ * \param[in] data     unused for single entry
+ *
+ * \retval             0 on success
+ * \retval             negative value on error
+ */
+int tgt_tot_pending_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = m->private;
+       struct tg_grants_data *tgd;
+
+       LASSERT(obd != NULL);
+       tgd = &obd->u.obt.obt_lut->lut_tgd;
+       seq_printf(m, "%llu\n", tgd->tgd_tot_pending);
+       return 0;
+}
+EXPORT_SYMBOL(tgt_tot_pending_seq_show);
+
+/**
+ * Show if grants compatibility mode is disabled.
+ *
+ * When tgd_grant_compat_disable is set, we don't grant any space to clients
+ * not supporting OBD_CONNECT_GRANT_PARAM. Otherwise, space granted to such
+ * a client is inflated since it consumes PAGE_SIZE of grant space per
+ * block, (i.e. typically 4kB units), but underlaying file system might have
+ * block size bigger than page size, e.g. ZFS. See LU-2049 for details.
+ *
+ * \param[in] m                seq_file handle
+ * \param[in] data     unused for single entry
+ *
+ * \retval             0 on success
+ * \retval             negative value on error
+ */
+int tgt_grant_compat_disable_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = m->private;
+       struct tg_grants_data *tgd = &obd->u.obt.obt_lut->lut_tgd;
+
+       seq_printf(m, "%u\n", tgd->tgd_grant_compat_disable);
+       return 0;
+}
+EXPORT_SYMBOL(tgt_grant_compat_disable_seq_show);
+
+/**
+ * Change grant compatibility mode.
+ *
+ * Setting tgd_grant_compat_disable prohibit any space granting to clients
+ * not supporting OBD_CONNECT_GRANT_PARAM. See details above.
+ *
+ * \param[in] file     proc file
+ * \param[in] buffer   string which represents mode
+ *                     1: disable compatibility mode
+ *                     0: enable compatibility mode
+ * \param[in] count    \a buffer length
+ * \param[in] off      unused for single entry
+ *
+ * \retval             \a count on success
+ * \retval             negative number on error
+ */
+ssize_t tgt_grant_compat_disable_seq_write(struct file *file,
+                                          const char __user *buffer,
+                                          size_t count, loff_t *off)
+{
+       struct seq_file *m = file->private_data;
+       struct obd_device *obd = m->private;
+       struct tg_grants_data *tgd = &obd->u.obt.obt_lut->lut_tgd;
+       bool val;
+       int rc;
+
+       rc = kstrtobool_from_user(buffer, count, &val);
+       if (rc)
+               return rc;
+
+       tgd->tgd_grant_compat_disable = val;
+
+       return count;
+}
+EXPORT_SYMBOL(tgt_grant_compat_disable_seq_write);