If a partial page is being truncated, the corresponding osc extent
should be held until the truncate finished.
Debug patch for osc_extent_wait() and don't wait for completion
of RPC it's not even sent in truncate.
Signed-off-by: Jinshan Xiong <jinshan.xiong@intel.com>
Change-Id: I96a5ec1fdbb3133c735ebdfdd0330a45a2a8ab1a
Reviewed-on: http://review.whamcloud.com/4317
Tested-by: Hudson
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Niu Yawei <niu@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
+static int extent_wait_cb(struct osc_extent *ext, int state)
+{
+ int ret;
+
+ osc_object_lock(ext->oe_obj);
+ ret = ext->oe_state == state;
+ osc_object_unlock(ext->oe_obj);
+
+ return ret;
+}
+
/**
* Wait for the extent's state to become @state.
*/
/**
* Wait for the extent's state to become @state.
*/
int state)
{
struct osc_object *obj = ext->oe_obj;
int state)
{
struct osc_object *obj = ext->oe_obj;
- 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);
osc_extent_release(env, ext);
/* wait for the extent until its state becomes @state */
osc_extent_release(env, ext);
/* wait for the extent until its state becomes @state */
- rc = l_wait_event(ext->oe_waitq, ext->oe_state == state, &lwi);
+ rc = l_wait_event(ext->oe_waitq, extent_wait_cb(ext, state), &lwi);
+ if (rc == -ETIMEDOUT) {
+ OSC_EXTENT_DUMP(D_ERROR, ext,
+ "%s: wait ext to %d timedout, recovery in progress?\n",
+ osc_export(obj)->exp_obd->obd_name, state);
+
+ lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
+ rc = l_wait_event(ext->oe_waitq, extent_wait_cb(ext, state),
+ &lwi);
+ }
if (rc == 0 && ext->oe_rc < 0)
rc = ext->oe_rc;
RETURN(rc);
if (rc == 0 && ext->oe_rc < 0)
rc = ext->oe_rc;
RETURN(rc);
* Discard pages with index greater than @size. If @ext is overlapped with
* @size, then partial truncate happens.
*/
* Discard pages with index greater than @size. If @ext is overlapped with
* @size, then partial truncate happens.
*/
-static int osc_extent_truncate(struct osc_extent *ext, pgoff_t trunc_index)
+static int osc_extent_truncate(struct osc_extent *ext, pgoff_t trunc_index,
+ bool partial)
{
struct cl_env_nest nest;
struct lu_env *env;
{
struct cl_env_nest nest;
struct lu_env *env;
/* only discard the pages with their index greater than
* trunc_index, and ... */
/* only discard the pages with their index greater than
* trunc_index, and ... */
- if (sub->cp_index < trunc_index) {
+ if (sub->cp_index < trunc_index ||
+ (sub->cp_index == trunc_index && partial)) {
/* accounting how many pages remaining in the chunk
* so that we can calculate grants correctly. */
if (sub->cp_index >> ppc_bits == trunc_chunk)
/* accounting how many pages remaining in the chunk
* so that we can calculate grants correctly. */
if (sub->cp_index >> ppc_bits == trunc_chunk)
--ext->oe_nr_pages;
++nr_pages;
}
--ext->oe_nr_pages;
++nr_pages;
}
- EASSERTF(ergo(ext->oe_start >= trunc_index, ext->oe_nr_pages == 0),
- ext, "trunc_index %lu\n", trunc_index);
+ EASSERTF(ergo(ext->oe_start >= trunc_index + !!partial,
+ ext->oe_nr_pages == 0),
+ ext, "trunc_index %lu, partial %d\n", trunc_index, partial);
osc_object_lock(obj);
if (ext->oe_nr_pages == 0) {
osc_object_lock(obj);
if (ext->oe_nr_pages == 0) {
pgoff_t index;
CFS_LIST_HEAD(list);
int result = 0;
pgoff_t index;
CFS_LIST_HEAD(list);
int result = 0;
ENTRY;
/* pages with index greater or equal to index will be truncated. */
ENTRY;
/* pages with index greater or equal to index will be truncated. */
- index = cl_index(osc2cl(obj), size + CFS_PAGE_SIZE - 1);
+ index = cl_index(osc2cl(obj), size);
+ partial = size > cl_offset(osc2cl(obj), index);
again:
osc_object_lock(obj);
again:
osc_object_lock(obj);
if (ext->oe_state != OES_TRUNC)
osc_extent_wait(env, ext, OES_TRUNC);
if (ext->oe_state != OES_TRUNC)
osc_extent_wait(env, ext, OES_TRUNC);
- rc = osc_extent_truncate(ext, index);
+ rc = osc_extent_truncate(ext, index, partial);
if (rc < 0) {
if (result == 0)
result = rc;
if (rc < 0) {
if (result == 0)
result = rc;
/* this must be an overlapped extent which means only
* part of pages in this extent have been truncated.
*/
/* this must be an overlapped extent which means only
* part of pages in this extent have been truncated.
*/
- EASSERTF(ext->oe_start < index, ext,
- "trunc index = %lu.\n", index);
+ EASSERTF(ext->oe_start <= index, ext,
+ "trunc index = %lu/%d.\n", index, partial);
/* fix index to skip this partially truncated extent */
index = ext->oe_end + 1;
/* fix index to skip this partially truncated extent */
index = ext->oe_end + 1;
/* we need to hold this extent in OES_TRUNC state so
* that no writeback will happen. This is to avoid
/* we need to hold this extent in OES_TRUNC state so
* that no writeback will happen. This is to avoid
struct obd_info oi_info;
struct obdo oi_oa;
struct osc_async_cbargs {
struct obd_info oi_info;
struct obdo oi_oa;
struct osc_async_cbargs {
int opc_rc;
cfs_completion_t opc_sync;
} oi_cbarg;
int opc_rc;
cfs_completion_t opc_sync;
} oi_cbarg;
&oinfo, NULL,
osc_async_upcall,
cbargs, PTLRPCD_SET);
&oinfo, NULL,
osc_async_upcall,
cbargs, PTLRPCD_SET);
+ cbargs->opc_rpc_sent = result == 0;
struct osc_io *oio = cl2osc_io(env, slice);
struct cl_object *obj = slice->cis_obj;
struct osc_async_cbargs *cbargs = &oio->oi_cbarg;
struct osc_io *oio = cl2osc_io(env, slice);
struct cl_object *obj = slice->cis_obj;
struct osc_async_cbargs *cbargs = &oio->oi_cbarg;
- int result;
-
- cfs_wait_for_completion(&cbargs->opc_sync);
- result = io->ci_result = cbargs->opc_rc;
+ if (cbargs->opc_rpc_sent) {
+ cfs_wait_for_completion(&cbargs->opc_sync);
+ result = io->ci_result = cbargs->opc_rc;
+ }
if (result == 0) {
if (oio->oi_lockless) {
/* lockless truncate */
if (result == 0) {
if (oio->oi_lockless) {
/* lockless truncate */