Whamcloud - gitweb
LU-13134 osc: re-declare ops_from/to to shrink osc_page
[fs/lustre-release.git] / lustre / osc / osc_cache.c
index 3214339..795040d 100644 (file)
@@ -38,6 +38,7 @@
 #define DEBUG_SUBSYSTEM S_OSC
 
 #include <lustre_osc.h>
+#include <lustre_dlm.h>
 
 #include "osc_internal.h"
 
@@ -536,6 +537,14 @@ static int osc_extent_merge(const struct lu_env *env, struct osc_extent *cur,
        if (cur->oe_max_end != victim->oe_max_end)
                return -ERANGE;
 
+       /*
+        * In the rare case max_pages_per_rpc (mppr) is changed, don't
+        * merge extents until after old ones have been sent, or the
+        * "extents are aligned to RPCs" checks are unhappy.
+        */
+       if (cur->oe_mppr != victim->oe_mppr)
+               return -ERANGE;
+
        LASSERT(cur->oe_dlmlock == victim->oe_dlmlock);
        ppc_bits = osc_cli(obj)->cl_chunkbits - PAGE_SHIFT;
        chunk_start = cur->oe_start >> ppc_bits;
@@ -561,7 +570,6 @@ static int osc_extent_merge(const struct lu_env *env, struct osc_extent *cur,
        cur->oe_urgent   |= victim->oe_urgent;
        cur->oe_memalloc |= victim->oe_memalloc;
        list_splice_init(&victim->oe_pages, &cur->oe_pages);
-       list_del_init(&victim->oe_link);
        victim->oe_nr_pages = 0;
 
        osc_extent_get(victim);
@@ -689,7 +697,7 @@ static struct osc_extent *osc_extent_find(const struct lu_env *env,
                cur->oe_start = descr->cld_start;
        if (cur->oe_end > max_end)
                cur->oe_end = max_end;
-       cur->oe_grants  = 0;
+       cur->oe_grants  = chunksize + cli->cl_grant_extent_tax;
        cur->oe_mppr    = max_pages;
        if (olck->ols_dlmlock != NULL) {
                LASSERT(olck->ols_hold);
@@ -757,54 +765,21 @@ restart:
                         * flushed, try next one. */
                        continue;
 
-               /* check if they belong to the same rpc slot before trying to
-                * merge. the extents are not overlapped and contiguous at
-                * chunk level to get here. */
-               if (ext->oe_max_end != max_end)
-                       /* if they don't belong to the same RPC slot or
-                        * max_pages_per_rpc has ever changed, do not merge. */
-                       continue;
-
-               /* check whether maximum extent size will be hit */
-               if ((ext_chk_end - ext_chk_start + 1 + 1) << ppc_bits >
-                   cli->cl_max_extent_pages)
-                       continue;
-
-               /* it's required that an extent must be contiguous at chunk
-                * level so that we know the whole extent is covered by grant
-                * (the pages in the extent are NOT required to be contiguous).
-                * Otherwise, it will be too much difficult to know which
-                * chunks have grants allocated. */
-
-               /* try to do front merge - extend ext's start */
-               if (chunk + 1 == ext_chk_start) {
-                       /* ext must be chunk size aligned */
-                       EASSERT((ext->oe_start & ~chunk_mask) == 0, ext);
-
-                       /* pull ext's start back to cover cur */
-                       ext->oe_start   = cur->oe_start;
-                       ext->oe_grants += chunksize;
+               if (osc_extent_merge(env, ext, cur) == 0) {
                        LASSERT(*grants >= chunksize);
                        *grants -= chunksize;
-
                        found = osc_extent_hold(ext);
-               } else if (chunk == ext_chk_end + 1) {
-                       /* rear merge */
-                       ext->oe_end     = cur->oe_end;
-                       ext->oe_grants += chunksize;
-                       LASSERT(*grants >= chunksize);
-                       *grants -= chunksize;
 
-                       /* try to merge with the next one because we just fill
-                        * in a gap */
+                       /*
+                        * Try to merge with the next one too because we
+                        * might have just filled in a gap.
+                        */
                        if (osc_extent_merge(env, ext, next_extent(ext)) == 0)
                                /* we can save extent tax from next extent */
                                *grants += cli->cl_grant_extent_tax;
 
-                       found = osc_extent_hold(ext);
-               }
-               if (found != NULL)
                        break;
+               }
        }
 
        osc_extent_tree_dump(D_CACHE, obj);
@@ -818,7 +793,6 @@ restart:
        } else if (conflict == NULL) {
                /* create a new extent */
                EASSERT(osc_extent_is_overlapped(obj, cur) == 0, cur);
-               cur->oe_grants = chunksize + cli->cl_grant_extent_tax;
                LASSERT(*grants >= cur->oe_grants);
                *grants -= cur->oe_grants;
 
@@ -1581,12 +1555,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;
 
@@ -1868,6 +1851,9 @@ can_merge(const struct osc_extent *ext, const struct osc_extent *in_rpc)
        if (in_rpc->oe_dio && overlapped(ext, in_rpc))
                return false;
 
+       if (ext->oe_is_rdma_only != in_rpc->oe_is_rdma_only)
+               return false;
+
        return true;
 }
 
@@ -1954,7 +1940,6 @@ static unsigned int get_write_extents(struct osc_object *obj,
        while (!list_empty(&obj->oo_hp_exts)) {
                ext = list_entry(obj->oo_hp_exts.next, struct osc_extent,
                                 oe_link);
-               LASSERT(ext->oe_state == OES_CACHE);
                if (!try_to_add_extent_for_io(cli, ext, &data))
                        return data.erd_page_count;
                EASSERT(ext->oe_nr_pages <= data.erd_max_pages, ext);
@@ -2338,7 +2323,7 @@ int osc_queue_async_io(const struct lu_env *env, struct cl_io *io,
 
        oap->oap_cmd = cmd;
        oap->oap_page_off = ops->ops_from;
-       oap->oap_count = ops->ops_to - ops->ops_from;
+       oap->oap_count = ops->ops_to - ops->ops_from + 1;
        /* No need to hold a lock here,
         * since this page is not in any list yet. */
        oap->oap_async_flags = 0;
@@ -2552,7 +2537,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;
@@ -2599,7 +2584,8 @@ int osc_queue_sync_pages(const struct lu_env *env, const struct cl_io *io,
                ++page_count;
                mppr <<= (page_count > mppr);
 
-               if (unlikely(opg->ops_from > 0 || opg->ops_to < PAGE_SIZE))
+               if (unlikely(opg->ops_from > 0 ||
+                            opg->ops_to < PAGE_SIZE - 1))
                        can_merge = false;
        }
 
@@ -2624,6 +2610,7 @@ int osc_queue_sync_pages(const struct lu_env *env, const struct cl_io *io,
        ext->oe_srvlock = !!(brw_flags & OBD_BRW_SRVLOCK);
        ext->oe_ndelay = !!(brw_flags & OBD_BRW_NDELAY);
        ext->oe_dio = !!(brw_flags & OBD_BRW_NOCACHE);
+       ext->oe_is_rdma_only = !!(brw_flags & OBD_BRW_RDMA_ONLY);
        ext->oe_nr_pages = page_count;
        ext->oe_mppr = mppr;
        list_splice_init(list, &ext->oe_pages);
@@ -2633,7 +2620,21 @@ int osc_queue_sync_pages(const struct lu_env *env, const struct cl_io *io,
        /* Reuse the initial refcount for RPC, don't drop it */
        osc_extent_state_set(ext, OES_LOCK_DONE);
        if (!ext->oe_rw) { /* write */
-               list_add_tail(&ext->oe_link, &obj->oo_urgent_exts);
+               if (!ext->oe_srvlock && !ext->oe_dio) {
+                       /* The most likely case here is from lack of grants
+                        * so we are either out of quota or out of space.
+                        * Since this means we are holding locks across
+                        * potentially multi-striped IO, we must send out
+                        * everything out instantly to avoid prolonged
+                        * waits resulting in lock eviction (likely since
+                        * the extended wait in osc_cache_enter() did not
+                        * yield any additional grant due to a timeout.
+                        * LU-13131 */
+                       ext->oe_hp = 1;
+                       list_add_tail(&ext->oe_link, &obj->oo_hp_exts);
+               } else {
+                       list_add_tail(&ext->oe_link, &obj->oo_urgent_exts);
+               }
                osc_update_pending(obj, OBD_BRW_WRITE, page_count);
        } else {
                list_add_tail(&ext->oe_link, &obj->oo_reading_exts);