X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fosc%2Fosc_cache.c;h=7711496fcbbe9f538b78fed3c5298aab42b62bc1;hb=63f298dcdd104bc1f229e04164c4a5d51c726283;hp=469de7f18cc381fcd769d81f429d1e3569fbd985;hpb=b74eb1a08d2a1cc1ee1b5b8aec268c05f8e7ac22;p=fs%2Flustre-release.git diff --git a/lustre/osc/osc_cache.c b/lustre/osc/osc_cache.c index 469de7f..7711496 100644 --- a/lustre/osc/osc_cache.c +++ b/lustre/osc/osc_cache.c @@ -27,7 +27,7 @@ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. * - * Copyright (c) 2012, Intel Corporation. + * Copyright (c) 2012, 2013, Intel Corporation. * */ /* @@ -99,22 +99,23 @@ static inline char list_empty_marker(cfs_list_t *list) #define EXTSTR "[%lu -> %lu/%lu]" #define EXTPARA(ext) (ext)->oe_start, (ext)->oe_end, (ext)->oe_max_end +static const char *oes_strings[] = { + "inv", "active", "cache", "locking", "lockdone", "rpc", "trunc", NULL }; #define OSC_EXTENT_DUMP(lvl, extent, fmt, ...) do { \ struct osc_extent *__ext = (extent); \ - const char *__str[] = OES_STRINGS; \ char __buf[16]; \ \ CDEBUG(lvl, \ "extent %p@{" EXTSTR ", " \ "[%d|%d|%c|%s|%s|%p], [%d|%d|%c|%c|%p|%u|%p]} " fmt, \ - /* ----- extent part 0 ----- */ \ + /* ----- extent part 0 ----- */ \ __ext, EXTPARA(__ext), \ /* ----- part 1 ----- */ \ cfs_atomic_read(&__ext->oe_refc), \ cfs_atomic_read(&__ext->oe_users), \ list_empty_marker(&__ext->oe_link), \ - __str[__ext->oe_state], ext_flags(__ext, __buf), \ + oes_strings[__ext->oe_state], ext_flags(__ext, __buf), \ __ext->oe_obj, \ /* ----- part 2 ----- */ \ __ext->oe_grants, __ext->oe_nr_pages, \ @@ -128,10 +129,10 @@ static inline char list_empty_marker(cfs_list_t *list) #undef EASSERTF #define EASSERTF(expr, ext, fmt, args...) do { \ if (!(expr)) { \ - OSC_EXTENT_DUMP(D_ERROR, (ext), fmt, ##args); \ - osc_extent_tree_dump(D_ERROR, (ext)->oe_obj); \ + OSC_EXTENT_DUMP(D_ERROR, (ext), fmt, ##args); \ + osc_extent_tree_dump(D_ERROR, (ext)->oe_obj); \ LASSERT(expr); \ - } \ + } \ } while (0) #undef EASSERT @@ -1283,8 +1284,6 @@ static int osc_completion(const struct lu_env *env, struct osc_async_page *oap, opg->ops_submit_time = 0; srvlock = oap->oap_brw_flags & OBD_BRW_SRVLOCK; - cl_page_completion(env, page, crt, rc); - /* statistic */ if (rc == 0 && srvlock) { struct lu_device *ld = opg->ops_cl.cpl_obj->co_lu.lo_dev; @@ -1303,24 +1302,25 @@ static int osc_completion(const struct lu_env *env, struct osc_async_page *oap, * reference counter protects page from concurrent reclaim. */ lu_ref_del(&page->cp_reference, "transfer", page); - /* - * As page->cp_obj is pinned by a reference from page->cp_req, it is - * safe to call cl_page_put() without risking object destruction in a - * non-blocking context. - */ - cl_page_put(env, page); + + cl_page_completion(env, page, crt, rc); + RETURN(0); } -#define OSC_DUMP_GRANT(cli, fmt, args...) do { \ +#define OSC_DUMP_GRANT(lvl, cli, fmt, args...) do { \ struct client_obd *__tmp = (cli); \ - CDEBUG(D_CACHE, "%s: { dirty: %ld/%ld dirty_pages: %d/%d " \ - "dropped: %ld avail: %ld, reserved: %ld, flight: %d } " fmt, \ + CDEBUG(lvl, "%s: grant { dirty: %ld/%ld dirty_pages: %d/%d " \ + "dropped: %ld avail: %ld, reserved: %ld, flight: %d } " \ + "lru {in list: %d, left: %d, waiters: %d }" fmt, \ __tmp->cl_import->imp_obd->obd_name, \ __tmp->cl_dirty, __tmp->cl_dirty_max, \ cfs_atomic_read(&obd_dirty_pages), obd_max_dirty_pages, \ __tmp->cl_lost_grant, __tmp->cl_avail_grant, \ - __tmp->cl_reserved_grant, __tmp->cl_w_in_flight, ##args); \ + __tmp->cl_reserved_grant, __tmp->cl_w_in_flight, \ + cfs_atomic_read(&__tmp->cl_lru_in_list), \ + cfs_atomic_read(&__tmp->cl_lru_busy), \ + cfs_atomic_read(&__tmp->cl_lru_shrinkers), ##args); \ } while (0) /* caller must hold loi_list_lock */ @@ -1461,7 +1461,7 @@ static int osc_enter_cache_try(struct client_obd *cli, { int rc; - OSC_DUMP_GRANT(cli, "need:%d.\n", bytes); + OSC_DUMP_GRANT(D_CACHE, cli, "need:%d.\n", bytes); rc = osc_reserve_grant(cli, bytes); if (rc < 0) @@ -1483,6 +1483,15 @@ static int osc_enter_cache_try(struct client_obd *cli, return rc; } +static int ocw_granted(struct client_obd *cli, struct osc_cache_waiter *ocw) +{ + int rc; + client_obd_list_lock(&cli->cl_loi_list_lock); + rc = cfs_list_empty(&ocw->ocw_entry); + client_obd_list_unlock(&cli->cl_loi_list_lock); + return rc; +} + /** * The main entry to reserve dirty page accounting. Usually the grant reserved * in this function will be freed in bulk in osc_free_grant() unless it fails @@ -1496,11 +1505,12 @@ static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli, struct osc_object *osc = oap->oap_obj; struct lov_oinfo *loi = osc->oo_oinfo; struct osc_cache_waiter ocw; - struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); + struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(600), NULL, + LWI_ON_SIGNAL_NOOP, NULL); int rc = -EDQUOT; ENTRY; - OSC_DUMP_GRANT(cli, "need:%d.\n", bytes); + OSC_DUMP_GRANT(D_CACHE, cli, "need:%d.\n", bytes); client_obd_list_lock(&cli->cl_loi_list_lock); @@ -1529,32 +1539,40 @@ static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli, ocw.ocw_rc = 0; client_obd_list_unlock(&cli->cl_loi_list_lock); - osc_io_unplug(env, cli, osc, PDL_POLICY_ROUND); + osc_io_unplug_async(env, cli, NULL); CDEBUG(D_CACHE, "%s: sleeping for cache space @ %p for %p\n", cli->cl_import->imp_obd->obd_name, &ocw, oap); - rc = l_wait_event(ocw.ocw_waitq, - cfs_list_empty(&ocw.ocw_entry), &lwi); + rc = l_wait_event(ocw.ocw_waitq, ocw_granted(cli, &ocw), &lwi); client_obd_list_lock(&cli->cl_loi_list_lock); - cfs_list_del_init(&ocw.ocw_entry); - if (rc < 0) - break; + /* l_wait_event is interrupted by signal, or timed out */ + if (rc < 0) { + if (rc == -ETIMEDOUT) { + OSC_DUMP_GRANT(D_ERROR, cli, + "try to reserve %d.\n", bytes); + osc_extent_tree_dump(D_ERROR, osc); + rc = -EDQUOT; + } + + cfs_list_del_init(&ocw.ocw_entry); + GOTO(out, rc); + } + + LASSERT(cfs_list_empty(&ocw.ocw_entry)); rc = ocw.ocw_rc; + if (rc != -EDQUOT) - break; - if (osc_enter_cache_try(cli, oap, bytes, 0)) { - rc = 0; - break; - } + GOTO(out, rc); + if (osc_enter_cache_try(cli, oap, bytes, 0)) + GOTO(out, rc = 0); } EXIT; - out: client_obd_list_unlock(&cli->cl_loi_list_lock); - OSC_DUMP_GRANT(cli, "returned %d.\n", rc); + OSC_DUMP_GRANT(D_CACHE, cli, "returned %d.\n", rc); RETURN(rc); } @@ -1566,31 +1584,25 @@ void osc_wake_cache_waiters(struct client_obd *cli) ENTRY; cfs_list_for_each_safe(l, tmp, &cli->cl_cache_waiters) { - /* if we can't dirty more, we must wait until some is written */ + ocw = cfs_list_entry(l, struct osc_cache_waiter, ocw_entry); + cfs_list_del_init(&ocw->ocw_entry); + + ocw->ocw_rc = -EDQUOT; + /* we can't dirty more */ if ((cli->cl_dirty + CFS_PAGE_SIZE > cli->cl_dirty_max) || (cfs_atomic_read(&obd_dirty_pages) + 1 > obd_max_dirty_pages)) { CDEBUG(D_CACHE, "no dirty room: dirty: %ld " "osc max %ld, sys max %d\n", cli->cl_dirty, cli->cl_dirty_max, obd_max_dirty_pages); - return; + goto wakeup; } - /* if still dirty cache but no grant wait for pending RPCs that - * may yet return us some grant before doing sync writes */ - if (cli->cl_w_in_flight && cli->cl_avail_grant < CFS_PAGE_SIZE) { - CDEBUG(D_CACHE, "%u BRW writes in flight, no grant\n", - cli->cl_w_in_flight); - return; - } - - ocw = cfs_list_entry(l, struct osc_cache_waiter, ocw_entry); - cfs_list_del_init(&ocw->ocw_entry); - ocw->ocw_rc = 0; if (!osc_enter_cache_try(cli, ocw->ocw_oap, ocw->ocw_grant, 0)) ocw->ocw_rc = -EDQUOT; +wakeup: CDEBUG(D_CACHE, "wake up %p for oap %p, avail grant %ld, %d\n", ocw, ocw->ocw_oap, cli->cl_avail_grant, ocw->ocw_rc); @@ -2125,23 +2137,24 @@ static void osc_check_rpcs(const struct lu_env *env, struct client_obd *cli, static int osc_io_unplug0(const struct lu_env *env, struct client_obd *cli, struct osc_object *osc, pdl_policy_t pol, int async) { - int has_rpcs = 1; int rc = 0; - client_obd_list_lock(&cli->cl_loi_list_lock); - if (osc != NULL) - has_rpcs = __osc_list_maint(cli, osc); - if (has_rpcs) { - if (!async) { - osc_check_rpcs(env, cli, pol); - } else { - CDEBUG(D_CACHE, "Queue writeback work for client %p.\n", - cli); - LASSERT(cli->cl_writeback_work != NULL); - rc = ptlrpcd_queue_work(cli->cl_writeback_work); - } + if (osc != NULL && osc_list_maint(cli, osc) == 0) + return 0; + + if (!async) { + /* disable osc_lru_shrink() temporarily to avoid + * potential stack overrun problem. LU-2859 */ + cfs_atomic_inc(&cli->cl_lru_shrinkers); + client_obd_list_lock(&cli->cl_loi_list_lock); + osc_check_rpcs(env, cli, pol); + client_obd_list_unlock(&cli->cl_loi_list_lock); + cfs_atomic_dec(&cli->cl_lru_shrinkers); + } else { + CDEBUG(D_CACHE, "Queue writeback work for client %p.\n", cli); + LASSERT(cli->cl_writeback_work != NULL); + rc = ptlrpcd_queue_work(cli->cl_writeback_work); } - client_obd_list_unlock(&cli->cl_loi_list_lock); return rc; } @@ -2444,10 +2457,11 @@ int osc_flush_async_page(const struct lu_env *env, struct cl_io *io, ext->oe_memalloc = 1; ext->oe_urgent = 1; - if (ext->oe_state == OES_CACHE && cfs_list_empty(&ext->oe_link)) { + if (ext->oe_state == OES_CACHE) { OSC_EXTENT_DUMP(D_CACHE, ext, "flush page %p make it urgent.\n", oap); - cfs_list_add_tail(&ext->oe_link, &obj->oo_urgent_exts); + if (cfs_list_empty(&ext->oe_link)) + cfs_list_add_tail(&ext->oe_link, &obj->oo_urgent_exts); unplug = true; } rc = 0; @@ -2624,6 +2638,8 @@ again: break; } + OSC_EXTENT_DUMP(D_CACHE, ext, "try to trunc:"LPU64".\n", size); + osc_extent_get(ext); if (ext->oe_state == OES_ACTIVE) { /* though we grab inode mutex for write path, but we @@ -2688,13 +2704,17 @@ again: osc_extent_put(env, ext); } if (waiting != NULL) { - if (result == 0) - result = osc_extent_wait(env, waiting, OES_INV); + int rc; + + /* ignore the result of osc_extent_wait the write initiator + * should take care of it. */ + rc = osc_extent_wait(env, waiting, OES_INV); + if (rc < 0) + OSC_EXTENT_DUMP(D_CACHE, waiting, "error: %d.\n", rc); osc_extent_put(env, waiting); waiting = NULL; - if (result == 0) - goto again; + goto again; } RETURN(result); } @@ -2830,10 +2850,9 @@ int osc_cache_writeback_range(const struct lu_env *env, struct osc_object *obj, ext->oe_urgent = 1; list = &obj->oo_urgent_exts; } - if (list != NULL) { + if (list != NULL) cfs_list_move_tail(&ext->oe_link, list); - unplug = true; - } + unplug = true; } else { /* the only discarder is lock cancelling, so * [start, end] must contain this extent */ @@ -2901,7 +2920,7 @@ int osc_cache_writeback_range(const struct lu_env *env, struct osc_object *obj, result = rc; } - OSC_IO_DEBUG(obj, "cache page out.\n"); + OSC_IO_DEBUG(obj, "pageout [%lu, %lu], %d.\n", start, end, result); RETURN(result); }