Whamcloud - gitweb
LU-13131 osc: Do not wait for grants for too long
[fs/lustre-release.git] / lustre / osc / osc_cache.c
index 1f343e2..93cd2d6 100644 (file)
@@ -38,6 +38,7 @@
 #define DEBUG_SUBSYSTEM S_OSC
 
 #include <lustre_osc.h>
+#include <lustre_dlm.h>
 
 #include "osc_internal.h"
 
@@ -110,7 +111,7 @@ static const char *oes_strings[] = {
                /* ----- extent part 0 ----- */                               \
                __ext, EXTPARA(__ext),                                        \
                /* ----- part 1 ----- */                                      \
-               atomic_read(&__ext->oe_refc),                                 \
+               kref_read(&__ext->oe_refc),                                   \
                atomic_read(&__ext->oe_users),                                \
                list_empty_marker(&__ext->oe_link),                           \
                oes_strings[__ext->oe_state], ext_flags(__ext, __buf),        \
@@ -186,10 +187,10 @@ static int osc_extent_sanity_check0(struct osc_extent *ext,
        if (ext->oe_state >= OES_STATE_MAX)
                GOTO(out, rc = 10);
 
-       if (atomic_read(&ext->oe_refc) <= 0)
+       if (kref_read(&ext->oe_refc) <= 0)
                GOTO(out, rc = 20);
 
-       if (atomic_read(&ext->oe_refc) < atomic_read(&ext->oe_users))
+       if (kref_read(&ext->oe_refc) < atomic_read(&ext->oe_users))
                GOTO(out, rc = 30);
 
        switch (ext->oe_state) {
@@ -329,7 +330,7 @@ static struct osc_extent *osc_extent_alloc(struct osc_object *obj)
        RB_CLEAR_NODE(&ext->oe_node);
        ext->oe_obj = obj;
        cl_object_get(osc2cl(obj));
-       atomic_set(&ext->oe_refc, 1);
+       kref_init(&ext->oe_refc);
        atomic_set(&ext->oe_users, 0);
        INIT_LIST_HEAD(&ext->oe_link);
        ext->oe_state = OES_INV;
@@ -340,35 +341,50 @@ static struct osc_extent *osc_extent_alloc(struct osc_object *obj)
        return ext;
 }
 
-static void osc_extent_free(struct osc_extent *ext)
+static void osc_extent_free(struct kref *kref)
 {
+       struct osc_extent *ext = container_of(kref, struct osc_extent,
+                                             oe_refc);
+
+       LASSERT(list_empty(&ext->oe_link));
+       LASSERT(atomic_read(&ext->oe_users) == 0);
+       LASSERT(ext->oe_state == OES_INV);
+       LASSERT(RB_EMPTY_NODE(&ext->oe_node));
+
+       if (ext->oe_dlmlock) {
+               lu_ref_del(&ext->oe_dlmlock->l_reference,
+                          "osc_extent", ext);
+               LDLM_LOCK_PUT(ext->oe_dlmlock);
+               ext->oe_dlmlock = NULL;
+       }
+#if 0
+       /* If/When cl_object_put drops the need for 'env',
+        * this code can be enabled, and matching code in
+        * osc_extent_put removed.
+        */
+       cl_object_put(osc2cl(ext->oe_obj));
+
        OBD_SLAB_FREE_PTR(ext, osc_extent_kmem);
+#endif
 }
 
 static struct osc_extent *osc_extent_get(struct osc_extent *ext)
 {
-       LASSERT(atomic_read(&ext->oe_refc) >= 0);
-       atomic_inc(&ext->oe_refc);
+       LASSERT(kref_read(&ext->oe_refc) >= 0);
+       kref_get(&ext->oe_refc);
        return ext;
 }
 
 static void osc_extent_put(const struct lu_env *env, struct osc_extent *ext)
 {
-       LASSERT(atomic_read(&ext->oe_refc) > 0);
-       if (atomic_dec_and_test(&ext->oe_refc)) {
-               LASSERT(list_empty(&ext->oe_link));
-               LASSERT(atomic_read(&ext->oe_users) == 0);
-               LASSERT(ext->oe_state == OES_INV);
-               LASSERT(RB_EMPTY_NODE(&ext->oe_node));
-
-               if (ext->oe_dlmlock != NULL) {
-                       lu_ref_del(&ext->oe_dlmlock->l_reference,
-                                  "osc_extent", ext);
-                       LDLM_LOCK_RELEASE(ext->oe_dlmlock);
-                       ext->oe_dlmlock = NULL;
-               }
+       LASSERT(kref_read(&ext->oe_refc) > 0);
+       if (kref_put(&ext->oe_refc, osc_extent_free)) {
+               /* This should be in osc_extent_free(), but
+                * while we need to pass 'env' it cannot be.
+                */
                cl_object_put(env, osc2cl(ext->oe_obj));
-               osc_extent_free(ext);
+
+               OBD_SLAB_FREE_PTR(ext, osc_extent_kmem);
        }
 }
 
@@ -379,9 +395,9 @@ static void osc_extent_put(const struct lu_env *env, struct osc_extent *ext)
  */
 static void osc_extent_put_trust(struct osc_extent *ext)
 {
-       LASSERT(atomic_read(&ext->oe_refc) > 1);
+       LASSERT(kref_read(&ext->oe_refc) > 1);
        assert_osc_object_is_locked(ext->oe_obj);
-       atomic_dec(&ext->oe_refc);
+       osc_extent_put(NULL, ext);
 }
 
 /**
@@ -593,7 +609,10 @@ int osc_extent_release(const struct lu_env *env, struct osc_extent *ext)
                        if (osc_extent_merge(env, ext, next_extent(ext)) == 0)
                                grant += cli->cl_grant_extent_tax;
 
-                       if (ext->oe_urgent)
+                       if (ext->oe_hp)
+                               list_move_tail(&ext->oe_link,
+                                              &obj->oo_hp_exts);
+                       else if (ext->oe_urgent)
                                list_move_tail(&ext->oe_link,
                                               &obj->oo_urgent_exts);
                        else if (ext->oe_nr_pages == ext->oe_mppr) {
@@ -1563,12 +1582,21 @@ static inline void cli_lock_after_unplug(struct client_obd *cli)
 static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli,
                           struct osc_async_page *oap, int bytes)
 {
-       struct osc_object       *osc = oap->oap_obj;
-       struct lov_oinfo        *loi = osc->oo_oinfo;
-       int                      rc = -EDQUOT;
-       unsigned long timeout = cfs_time_seconds(AT_OFF ? obd_timeout : at_max);
+       struct osc_object *osc = oap->oap_obj;
+       struct lov_oinfo *loi = osc->oo_oinfo;
+       int rc = -EDQUOT;
        int remain;
        bool entered = false;
+       /* We cannot wait for a long time here since we are holding ldlm lock
+        * across the actual IO. If no requests complete fast (e.g. due to
+        * overloaded OST that takes a long time to process everything, we'd
+        * get evicted if we wait for a normal obd_timeout or some such.
+        * So we try to wait half the time it would take the client to be
+        * evicted by server which is half obd_timeout when AT is off
+        * or at least ldlm_enqueue_min with AT on.
+        * See LU-13131 */
+       unsigned long timeout = cfs_time_seconds(AT_OFF ? obd_timeout / 2 :
+                                                         ldlm_enqueue_min / 2);
 
        ENTRY;
 
@@ -2152,7 +2180,12 @@ __must_hold(&cli->cl_loi_list_lock)
 
                OSC_IO_DEBUG(osc, "%lu in flight\n", rpcs_in_flight(cli));
 
-               if (osc_max_rpc_in_flight(cli, osc)) {
+               /* even if we have reached our max in flight RPCs, we still
+                * allow all high-priority RPCs through to prevent their
+                * starvation and leading to server evicting us for not
+                * writing out pages in a timely manner LU-13131 */
+               if (osc_max_rpc_in_flight(cli, osc) &&
+                   list_empty(&osc->oo_hp_exts)) {
                        __osc_list_maint(cli, osc);
                        break;
                }
@@ -2529,7 +2562,7 @@ int osc_flush_async_page(const struct lu_env *env, struct cl_io *io,
        oap->oap_async_flags |= ASYNC_READY|ASYNC_URGENT;
        spin_unlock(&oap->oap_lock);
 
-       if (memory_pressure_get())
+       if (current->flags & PF_MEMALLOC)
                ext->oe_memalloc = 1;
 
        ext->oe_urgent = 1;
@@ -2875,7 +2908,7 @@ int osc_cache_writeback_range(const struct lu_env *env, struct osc_object *obj,
                                        EASSERT(!ext->oe_hp, ext);
                                        ext->oe_hp = 1;
                                        list = &obj->oo_hp_exts;
-                               } else if (!ext->oe_urgent) {
+                               } else if (!ext->oe_urgent && !ext->oe_hp) {
                                        ext->oe_urgent = 1;
                                        list = &obj->oo_urgent_exts;
                                }