{"action":"opened","issue":{"url":"https://api.github.com/repos/pscedu/slash2/issues/261","labels_url":"https://api.github.com/repos/pscedu/slash2/issues/261/labels{/name}","comments_url":"https://api.github.com/repos/pscedu/slash2/issues/261/comments","events_url":"https://api.github.com/repos/pscedu/slash2/issues/261/events","html_url":"https://github.com/pscedu/slash2/issues/261","id":89860756,"number":261,"title":"mount_slash fails when aio spans two bmaps","user":{"login":"slovichon","id":6945653,"avatar_url":"https://avatars.githubusercontent.com/u/6945653?v=3","gravatar_id":"","url":"https://api.github.com/users/slovichon","html_url":"https://github.com/slovichon","followers_url":"https://api.github.com/users/slovichon/followers","following_url":"https://api.github.com/users/slovichon/following{/other_user}","gists_url":"https://api.github.com/users/slovichon/gists{/gist_id}","starred_url":"https://api.github.com/users/slovichon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/slovichon/subscriptions","organizations_url":"https://api.github.com/users/slovichon/orgs","repos_url":"https://api.github.com/users/slovichon/repos","events_url":"https://api.github.com/users/slovichon/events{/privacy}","received_events_url":"https://api.github.com/users/slovichon/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/pscedu/slash2/labels/bug","name":"bug","color":"fc2929"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-06-21T04:02:05Z","updated_at":"2015-06-21T04:02:05Z","closed_at":null,"body":"\nOriginal attachment names and IDs:\n- _bug261.diff_ (ID 5)\n\nOn 2012-04-04 20:58:47 -0400, Paul Nowoczynski wrote:\n\n> ```\nThe first biorq was presumably handled by the cache and was already destroyed by the time the AIO handler tried to deal with the second biorq.\n> \n> (gdb) bt\n> # 0  0x00002aaaab9d7885 in raise () from /lib64/libc.so.6\n> # 1  0x00002aaaab9d9065 in abort () from /lib64/libc.so.6\n> # 2  0x00000000004f95c6 in _psclogv (pci=0x2aab20000a20, level=PLL_FATAL, options=0, fmt=0x632750 \"[assert] %s\", \n>     ap=0x2aab183ffa50) at /local/src/p/psc_fsutil_libs/psc_util/log.c:395\n> # 3  0x00000000004f97bd in _psc_fatal (pci=0x2aab20000a20, level=PLL_FATAL, options=0, fmt=0x632750 \"[assert] %s\")\n>     at /local/src/p/psc_fsutil_libs/psc_util/log.c:427\n> # 4  0x000000000053cc53 in msl_fsrq_completion_try (q=0x2aaab0020bc0)\n>     at /local/src/p/slash_nara/mount_slash/mount_slash_int.c:909\n> # 5  0x000000000053f1d3 in msl_bmpce_aio_process (e=0x2aab78246010)\n>     at /local/src/p/slash_nara/mount_slash/mount_slash_int.c:956\n> # 6  0x000000000054114e in _msl_bmpce_rpc_done (pci=0x2aab20000a20, e=0x2aab78246010, rc=0)\n>     at /local/src/p/slash_nara/mount_slash/mount_slash_int.c:1007\n> # 7  0x0000000000542664 in msl_read_cb (rq=0x128f290, rc=0, args=0xcd4210)\n>     at /local/src/p/slash_nara/mount_slash/mount_slash_int.c:1051\n> # 8  0x00000000005a218b in slc_rci_handle_io (rq=0x128f290) at /local/src/p/slash_nara/mount_slash/rci.c:173\n> # 9  0x00000000005a32be in slc_rci_handler (rq=0x128f290) at /local/src/p/slash_nara/mount_slash/rci.c:203\n> # 10 0x00000000005edef5 in pscrpc_server_handle_request (svc=0x1022010, thread=0x2aab200008c0)\n>     at /local/src/p/psc_fsutil_libs/psc_rpc/service.c:388\n> # 11 0x00000000005f2e38 in pscrpcthr_main (thr=0x2aab200008c0)\n>     at /local/src/p/psc_fsutil_libs/psc_rpc/service.c:758\n> # 12 0x00000000005ff3eb in _pscthr_begin (arg=0x7fffffffd970) at /local/src/p/psc_fsutil_libs/psc_util/thread.c:311\n> # 13 0x00002aaaab7907f1 in start_thread () from /lib64/libpthread.so.0\n> # 14 0x00002aaaaba8a92d in clone () from /lib64/libc.so.6\n> \n> (gdb) call dump_biorq_flags(257)\n> BIORQ_READ|BIORQ_DESTROY\n> \n> (gdb) p *(struct bmpc_ioreq *)0xd13400\n> $20 = {biorq_off = 134152192, biorq_len = 65536, biorq_flags = 257, biorq_retries = 0, \n>   biorq_last_sliod = 4294967295, biorq_lock = {psl_value = {value32 = 2}, psl_flags = 0, psl_owner = 0}, \n>   biorq_issue = {tv_sec = 1333577554, tv_nsec = 465717931}, biorq_expire = {tv_sec = 1333577554, \n>     tv_nsec = 475717931}, biorq_pages = {pda_flags = 0, pda_pos = 0, pda_nalloc = 0, pda_items = 0x0}, \n>   biorq_lentry = {plh_next = 0xd13850, plh_prev = 0xcef460, plh_magic = 1311693406324658740, \n>     plh_owner = 0xce62b0}, biorq_mfh_lentry = {plh_next = 0x0, plh_prev = 0x0, plh_magic = 1311693406324658740, \n>     plh_owner = 0x0}, biorq_bwc_lentry = {plh_next = 0x0, plh_prev = 0x0, plh_magic = 1311693406324658740, \n>     plh_owner = 0x0}, biorq_bmap = 0xc95010, biorq_rqset = 0x0, biorq_waitq = {wq_mut = {pm_mutex = {__data = {\n>           __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = -1, __spins = 0, __list = {__prev = 0x0, \n>             __next = 0x0}}, __size = '\\000' <repeats 16 times>\"\\377, \\377\\377\\377\", '\\000' <repeats 19 times>, \n>         __align = 0}, pm_owner = 0}, wq_cond = {__data = {__lock = 1, __futex = 0, \n>         __total_seq = 18446744073709551615, __wakeup_seq = 0, __woken_seq = 0, __mutex = 0x0, __nwaiters = 0, \n>         __broadcast_seq = 0}, \n>       __size = \"\\001\\000\\000\\000\\000\\000\\000\\000\\377\\377\\377\\377\\377\\377\\377\\377\", '\\000' <repeats 31 times>, \n>       __align = 1}, wq_nwaiters = {value32 = 0}}, biorq_fhent = 0x2aabb8126e20, biorq_fsrqi = 0x2aaab0020bc0}\n> \n> (gdb) call dump_biorq_flags(16561)\n> BIORQ_READ|BIORQ_SCHED|BIORQ_INFL|BIORQ_FORCE_EXPIRE|BIORQ_AIOWAIT\n> \n> (gdb) p *(struct bmpc_ioreq *)0xcef6a0\n> $21 = {biorq_off = 0, biorq_len = 65536, biorq_flags = 16561, biorq_retries = 0, biorq_last_sliod = 4294967295, \n>   biorq_lock = {psl_value = {value32 = 2}, psl_flags = 0, psl_owner = 0}, biorq_issue = {tv_sec = 1333577554, \n>     tv_nsec = 481862517}, biorq_expire = {tv_sec = 1333577554, tv_nsec = 491862517}, biorq_pages = {\n>     pda_flags = 0, pda_pos = 2, pda_nalloc = 2, pda_items = 0x2aaab00213e0}, biorq_lentry = {plh_next = 0xc954a8, \n>     plh_prev = 0xc954a8, plh_magic = 1311693406324658740, plh_owner = 0xc954a8}, biorq_mfh_lentry = {\n>     plh_next = 0x2aabb8126e68, plh_prev = 0x2aabb8126e68, plh_magic = 1311693406324658740, \n>     plh_owner = 0x2aabb8126e68}, biorq_bwc_lentry = {plh_next = 0x0, plh_prev = 0x0, \n>     plh_magic = 1311693406324658740, plh_owner = 0x0}, biorq_bmap = 0xc95320, biorq_rqset = 0x0, biorq_waitq = {\n>     wq_mut = {pm_mutex = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 2, __spins = 0, \n>           __list = {__prev = 0x0, __next = 0x0}}, \n>         __size = '\\000' <repeats 16 times>, \"\\002\", '\\000' <repeats 22 times>, __align = 0}, pm_owner = 0}, \n>     wq_cond = {__data = {__lock = 0, __futex = 0, __total_seq = 0, __wakeup_seq = 0, __woken_seq = 0, \n>         __mutex = 0x0, __nwaiters = 0, __broadcast_seq = 0}, __size = '\\000' <repeats 47 times>, __align = 0}, \n>     wq_nwaiters = {value32 = 0}}, biorq_fhent = 0x2aabb8126e20, biorq_fsrqi = 0x2aaab0020bc0}\n> (gdb) call dump_biorq_flags(16561)\n> BIORQ_READ|BIORQ_SCHED|BIORQ_INFL|BIORQ_FORCE_EXPIRE|BIORQ_AIOWAIT\n> (gdb) p *q\n> $22 = {mfsrq_biorq = {0xd13400, 0xcef6a0, 0x0, 0x0}, mfsrq_bmpceatt = 0x2aab78246010, mfsrq_fh = 0x2aabb8126e20, \n>   mfsrq_buf = 0x2aaab0000bb0 \"A\\240\\370\\070\\001z\\216\\234fb\\331\\301D2p\\246\\231\\315ï¿½YQ*b\\262\", \n>   mfsrq_size = 131072, mfsrq_off = 134152192, mfsrq_flags = 7, mfsrq_err = 0, mfsrq_ref = 0, mfsrq_rw = SL_READ, \n>   mfsrq_pfr = 0x9d5300, mfsrq_lentry = {plh_next = 0x0, plh_prev = 0x0, plh_magic = 1311693406324658740, \n>     plh_owner = 0x0}}\n> (gdb)\n```\nOn 2012-04-05 18:56:02 -0400, Paul Nowoczynski wrote:\n\n> ```\nCreated attachment 5\n> Here's a potential patch to fix this problem.  It addresses mixed AIO and cached I/O requests which inter-bmap IOs.\n> \n> Here's a potential patch to fix this problem.  It addresses mixed AIO and cached I/O requests which inter-bmap IOs.\n```\nOn 2012-04-05 18:56:42 -0400, Paul Nowoczynski wrote:\n\n> ```\nIndex: mount_slash/mount_slash.h\n> ===================================================================\n> --- mount_slash/mount_slash.h\t(revision 19009)\n> +++ mount_slash/mount_slash.h\t(working copy)\n> @@ -135,6 +135,8 @@\n>  \n>  #define MAX_BMAPS_REQ\t\t\t4\n>  \n> +#define MSL_BIORQ_COMPLETE\t((void *)0x1)\n> +\n>  struct slc_async_req {\n>  \tstruct psc_listentry\t\t  car_lentry;\n>  \tstruct pscrpc_async_args\t  car_argv;\n> @@ -194,6 +196,7 @@\n>  \n>  void\tmsl_fsrqinfo_write(struct msl_fsrqinfo *);\n>  int\tmsl_fsrqinfo_state(struct msl_fsrqinfo *, int, int, int);\n> +void    msl_fsrqinfo_biorq_add(struct msl_fsrqinfo *, struct bmpc_ioreq *,int);\n>  \n>  #define msl_fsrqinfo_isset(q, f)\tmsl_fsrqinfo_state((q), (f), 0, 0)\n>  #define msl_fsrqinfo_aioisset(q)\tmsl_fsrqinfo_state((q), MFSRQ_AIOWAIT, 0, 0)\n> @@ -248,7 +251,7 @@\n>  int\t msl_write_rpc_cb(struct pscrpc_request *, struct pscrpc_async_args *);\n>  int\t msl_write_rpcset_cb(struct pscrpc_request_set *, void *, int);\n>  \n> -size_t\t msl_pages_copyout(struct bmpc_ioreq *, char *);\n> +size_t\t msl_pages_copyout(struct bmpc_ioreq *);\n>  \n>  struct slashrpc_cservice *\n>  \t msl_try_get_replica_res(struct bmapc_memb *, int);\n> Index: mount_slash/mount_slash_int.c\n> ===================================================================\n> --- mount_slash/mount_slash_int.c\t(revision 19009)\n> +++ mount_slash/mount_slash_int.c\t(working copy)\n> @@ -110,13 +110,13 @@\n>   * Notes: roff is bmap aligned.\n>   */\n>  __static void\n> -msl_biorq_build(struct bmpc_ioreq **newreq, struct bmapc_memb *b,\n> -\tstruct msl_fhent *mfh, struct msl_fsrqinfo *q, uint32_t roff,\n> -\tuint32_t len, int op)\n> +msl_biorq_build(struct msl_fsrqinfo *q, struct bmapc_memb *b, char *buf,\n> +    int rqnum, uint32_t roff, uint32_t len, int op)\n>  {\n>  \tstruct bmpc_ioreq *r;\n>  \tstruct bmap_pagecache *bmpc;\n>  \tstruct bmap_pagecache_entry *e, bmpce_search, *bmpce_new;\n> +\tstruct msl_fhent *mfh = q->mfsrq_fh;\n>  \tuint32_t aoff = (roff & ~BMPC_BUFMASK); /* aligned, relative offset */\n>  \tuint32_t alen = len + (roff & BMPC_BUFMASK);\n>  \tuint64_t foff = roff + bmap_foff(b); /* filewise offset */\n> @@ -136,7 +136,7 @@\n>  \n>  \tmsl_update_iocounters(len);\n>  \n> -\t*newreq = r = bmpc_biorq_new(b, mfh, q, roff, len, op);\n> +\tr = bmpc_biorq_new(q, b, buf, rqnum, roff, len, op);\n>  \tif (r->biorq_flags & BIORQ_DIO)\n>  \t\t/* The bmap is set to use directio, we may then skip\n>  \t\t * cache preparation.\n> @@ -164,6 +164,7 @@\n>  \t}\n>  \n>  \tpsc_assert(npages <= BMPC_IOMAXBLKS);\n> +\n>  \tif (op == BIORQ_WRITE)\n>  \t\tmaxpages = npages;\n>  \telse {\n> @@ -171,7 +172,7 @@\n>  \t\t *    that could be acquired from this bmap.\n>  \t\t */\n>  \t\tint rapages;\n> -\n> +\t\t\n>  \t\t/* First, query the read ahead struct in the mfh to\n>  \t\t *   obtain rapages and ra direction.\n>  \t\t */\n> @@ -182,30 +183,29 @@\n>  \t\t\tpsc_assert(bkwdra == 0 || bkwdra == 1);\n>  \t\t\tn = bkwdra ? (aoff / BMPC_BLKSZ) :\n>  \t\t\t\t(SLASH_BMAP_SIZE - aoff) / BMPC_BLKSZ;\n> -\n> -\t\t\t/* Read ahead must be contained within this bmap.\n> +\t\t\t/* Read ahead must be contained within this bmap\n>  \t\t\t */\n>  \t\t\tmaxpages = MIN(rapages, n);\n>  \t\t\tif (!bkwdra) {\n>  \t\t\t\t/* Don't prefetch past EOF\n>  \t\t\t\t */\n>  \t\t\t\tn = ((fsz - (bmap_foff(b) + roff)) /\n> -\t\t\t\t     BMPC_BLKSZ) +\n> +\t\t\t\t    BMPC_BLKSZ) +\n>  \t\t\t\t\t((fsz % BMPC_BLKSZ) ? 1 : 0);\n>  \n>  \t\t\t\tmaxpages = MIN(maxpages, n);\n>  \t\t\t}\n>  \t\t\tif (maxpages < npages)\n>  \t\t\t\tmaxpages = npages;\n> -\n> +\t\t\t\n>  \t\t\tDEBUG_BMAP(PLL_INFO, b, \"maxpages=%d npages=%d \"\n> -\t\t\t   \"bkwdra=%d\", maxpages, npages, bkwdra);\n> +\t\t\t    \"bkwdra=%d\", maxpages, npages, bkwdra);\n>  \t\t} else {\n>  \t\t\tmaxpages = npages;\n>  \t\t\tbkwdra = 0;\n>  \t\t}\n>  \t}\n> -\n> +\t\n>  \t/* Lock the bmap's page cache and try to locate cached pages\n>  \t *   which correspond to this request.\n>  \t */\n> @@ -839,8 +839,7 @@\n>  msl_fsrq_complete(struct msl_fsrqinfo *q)\n>  {\n>  \tstruct bmpc_ioreq *r;\n> -\tsize_t len, rc;\n> -\tchar *buf = q->mfsrq_buf;\n> +\tsize_t len = 0, rc;\n>  \tint i;\n>  \n>  \tpsc_assert(!q->mfsrq_ref);\n> @@ -848,7 +847,7 @@\n>  \tfor (i = 0, len = 0; i < MAX_BMAPS_REQ; i++) {\n>  \t\tr = q->mfsrq_biorq[i];\n>  \t\tif (!r)\n> -\t\t\tbreak;\n> +\t\t\tcontinue;\n>  \n>  \t\tBIORQ_LOCK(r);\n>  \t\tr->biorq_flags &= ~(BIORQ_INFL | BIORQ_SCHED);\n> @@ -856,27 +855,42 @@\n>  \t\tBIORQ_ULOCK(r);\n>  \n>  \t\tDEBUG_BIORQ(PLL_INFO, r, \"fsrq_complete\");\n> -\t\tif (q->mfsrq_err)\n> +\n> +\t\t/* Aio writes are handled server side.\n> +\t\t */\n> +\t\tif (q->mfsrq_rw != SL_READ)\n> +\t\t\tabort();\n> +\n> +\t\tpsc_assert(r->biorq_flags & BIORQ_READ);\n> +\t\t\n> +\t\tif (q->mfsrq_err) {\n>  \t\t\tmsl_biorq_destroy(r);\n> +\t\t\tcontinue;\n> +\t\t}\n>  \n> -\t\telse if (q->mfsrq_rw == SL_READ) {\n> -\t\t\tpsc_assert(r->biorq_flags & BIORQ_READ);\n> +\t\tif (i && !len)\n> +\t\t\t/* This fsrq has 2 biorqs (probably spanned 2 bmaps)\n> +\t\t\t * and the first biorq was completed via cache so\n> +\t\t\t * interpolate its len.\n> +\t\t\t */\n> +\t\t\tlen = q->mfsrq_size - r->biorq_len;\n> +\n> +\t\tif (r->biorq_flags & BIORQ_DIO) {\n>  \t\t\t/* Support mix of dio and cached reads.  This may occur\n> -\t\t\t *   if the read request spans bmaps.\n> +\t\t\t * if the read request spans bmaps.  The 'len' here was\n> +\t\t\t * possibly adjusted against the tail of the file in\n> +\t\t\t * msl_io.\n>  \t\t\t */\n> -\t\t\tif (r->biorq_flags & BIORQ_DIO) {\n> -\t\t\t\tlen += r->biorq_len;\n> -\t\t\t\tmsl_biorq_destroy(r);\n> -\t\t\t} else {\n> -\t\t\t\trc = msl_pages_copyout(r, buf);\n> -\t\t\t\tif (!rc)\n> -\t\t\t\t\tbreak;\n> -\t\t\t\tlen += rc;\n> -\t\t\t}\n> -\t\t\tbuf += len;\n> +\t\t\tlen += r->biorq_len;\n> +\t\t\tmsl_biorq_destroy(r);\n> +\n> +\t\t} else {\n> +\t\t\trc = msl_pages_copyout(r);\n> +\t\t\tif (!rc)\n> +\t\t\t\tbreak;\n> +\t\t\tlen += rc;\n>  \t\t\tpsc_assert(len <= q->mfsrq_size);\n> -\t\t} else\n> -\t\t\tabort();\n> +\t\t}\n>  \t}\n>  \n>  \tif (!q->mfsrq_err) {\n> @@ -903,9 +917,11 @@\n>  \t */\n>  \tfor (i = 0; i < MAX_BMAPS_REQ; i++) {\n>  \t\tr = q->mfsrq_biorq[i];\n> -\t\tif (!r)\n> -\t\t\tbreak;\n> +\t\tpsc_assert(r);\n>  \n> +\t\tif (r == MSL_BIORQ_COMPLETE)\n> +\t\t\tcontinue;\n> +\n>  \t\tpsc_assert(r->biorq_flags & BIORQ_AIOWAIT);\n>  \n>  \t\tDYNARRAY_FOREACH(e, j, &r->biorq_pages) {\n> @@ -946,11 +962,14 @@\n>  \tstruct psc_dynarray a = DYNARRAY_INIT;\n>  \tint i;\n>  \n> +\t/* If fsrq cannot be completed. msl_fsrq_completion_try()\n> +\t * will reattach it to another aio'd bmpce.\n> +\t */\n>  \twhile ((q = pll_get(&e->bmpce_pndgaios)))\n> +\t\t/* msl_fsrq_completion_try() may remove 'e' so loop\n> +\t\t * gather work before calling msl_fsrq_completion_try().\n> +\t\t */\n>  \t\tpsc_dynarray_add(&a, q);\n> -\t\t/* If fsrq cannot be completed. msl_fsrq_completion_try()\n> -\t\t *   will reattach it to another aio'd bmpce.\n> -\t\t */\n>  \n>  \tDYNARRAY_FOREACH(q, i, &a) {\n>  \t\tmsl_fsrq_completion_try(q);\n> @@ -1247,7 +1266,7 @@\n>  }\n>  \n>  __static int\n> -msl_pages_dio_getput(struct bmpc_ioreq *r, char *bufp)\n> +msl_pages_dio_getput(struct bmpc_ioreq *r)\n>  {\n>  \tstruct slashrpc_cservice  *csvc = NULL;\n>  \tstruct pscrpc_request\t  *rq = NULL;\n> @@ -1297,8 +1316,7 @@\n>  \t\trq->rq_interpret_reply = msl_dio_cb0;\n>  \t\trq->rq_async_args.pointer_arg[MSL_CBARG_CSVC] = csvc;\n>  \t\trq->rq_async_args.pointer_arg[MSL_CBARG_BIORQ] = r;\n> -\t\trq->rq_async_args.pointer_arg[MSL_CBARG_BUF] = bufp + nbytes;\n> -\t\tiovs[i].iov_base = bufp + nbytes;\n> +\t\tiovs[i].iov_base = r->biorq_buf + nbytes;\n>  \t\tiovs[i].iov_len  = len;\n>  \n>  \t\trc = rsx_bulkclient(rq, (op == SRMT_WRITE ?\n> @@ -1337,9 +1355,9 @@\n>  \tswitch (rc) {\n>  \tcase 0:\n>  \t\tpsc_iostats_intv_add((op == SRMT_WRITE ?\n> -\t\t\t\t      &msl_diowr_stat : &msl_diord_stat), size);\n> +\t\t\t&msl_diowr_stat : &msl_diord_stat), size);\n>  \n> -\t\tmsl_biorq_destroy(r);\t\t\n> +\t\tmsl_biorq_destroy(r);\n>  \t\tbreak;\n>  \n>  \tcase -SLERR_AIOWAIT:\n> @@ -1893,16 +1911,16 @@\n>   * @buf: the source (application) buffer.\n>   */\n>  __static size_t\n> -msl_pages_copyin(struct bmpc_ioreq *r, char *buf)\n> +msl_pages_copyin(struct bmpc_ioreq *r)\n>  {\n>  \tstruct bmap_pagecache_entry *e;\n>  \tuint32_t toff, tsize, nbytes;\n>  \tchar *dest, *src;\n>  \tint i;\n>  \n> -\tsrc    = buf;\n> -\ttsize  = r->biorq_len;\n> -\ttoff   = r->biorq_off;\n> +\tsrc = r->biorq_buf;\n> +\ttsize = r->biorq_len;\n> +\ttoff = r->biorq_off;\n>  \n>  \tDYNARRAY_FOREACH(e, i, &r->biorq_pages) {\n>  \t\t/* All pages are involved, therefore tsize should have value.\n> @@ -1977,7 +1995,7 @@\n>   * msl_pages_copyout - Copy pages to the user application buffer.\n>   */\n>  size_t\n> -msl_pages_copyout(struct bmpc_ioreq *r, char *buf)\n> +msl_pages_copyout(struct bmpc_ioreq *r)\n>  {\n>  \tstruct bmap_pagecache_entry *e;\n>  \tsize_t nbytes, tbytes=0, rflen;\n> @@ -1985,10 +2003,10 @@\n>  \tchar *dest, *src;\n>  \toff_t toff;\n>  \n> -\tdest   = buf;\n> -\ttoff   = r->biorq_off;\n> +\tdest = r->biorq_buf;\n> +\ttoff = r->biorq_off;\n>  \n> -\trflen  = fcmh_getsize(r->biorq_bmap->bcm_fcmh) -\n> +\trflen = fcmh_getsize(r->biorq_bmap->bcm_fcmh) -\n>  \t\tbmap_foff(r->biorq_bmap);\n>  \n>  \tif (biorq_voff_get(r) > rflen) {\n> @@ -2203,13 +2221,16 @@\n>  \tpscfs_reply_write(q->mfsrq_pfr, q->mfsrq_size, rc);\n>  }\n>  \n> -__static void\n> -msl_fsrqinfo_biorq_add(struct msl_fsrqinfo *q, struct bmpc_ioreq *r,\n> -    int pos)\n> +void\n> +msl_fsrqinfo_biorq_add(struct msl_fsrqinfo *q, struct bmpc_ioreq *r, \n> +    int biorq_num)\n>  {\n> +\tpsc_assert(q->mfsrq_fh == r->biorq_fhent);\n> +\n>  \tMFH_LOCK(r->biorq_fhent);\n> -\tDEBUG_BIORQ(PLL_INFO, r, \"q=%p pos=%d\", q, pos);\n> -\tq->mfsrq_biorq[pos] = r;\n> +\tDEBUG_BIORQ(PLL_INFO, r, \"q=%p pos=%d\", q, biorq_num);\n> +\tpsc_assert(!q->mfsrq_biorq[biorq_num]);\n> +\tq->mfsrq_biorq[biorq_num] = r;\n>  \tMFH_ULOCK(r->biorq_fhent);\n>  }\n>  \n> @@ -2235,6 +2256,8 @@\n>  \t} else {\n>  \t\tint i;\n>  \n> +\t\tpsc_enter_debugger(\"\");\n> +\n>  \t\t/* The fs request was reissued.  Clear out any old state.\n>  \t\t */\n>  \t\tpsc_assert(q->mfsrq_fh == mfh &&\n> @@ -2246,9 +2269,10 @@\n>  \n>  \t\tfor (i = 0; i < MAX_BMAPS_REQ; i++) {\n>  \t\t\tif (!q->mfsrq_biorq[i])\n> -\t\t\t\tbreak;\n> +\t\t\t\tcontinue;\n>  \n>  \t\t\tmsl_biorq_destroy(q->mfsrq_biorq[i]);\n> +\t\t\tq->mfsrq_biorq[i] = NULL;\n>  \t\t}\n>  \t}\n>  \treturn (q);\n> @@ -2274,10 +2298,10 @@\n>  msl_io(struct pscfs_req *pfr, struct msl_fhent *mfh, char *buf,\n>      const size_t size, const off_t off, enum rw rw)\n>  {\n> -\tstruct bmpc_ioreq *r[MAX_BMAPS_REQ];\n>  \tstruct bmapc_memb *b, *bref = NULL;\n>  \tstruct fidc_membh *f;\n>  \tstruct msl_fsrqinfo *q;\n> +\tstruct bmpc_ioreq *r;\n>  \tsize_t s, e, tlen, tsize;\n>  \tuint64_t fsz;\n>  \tssize_t rc;\n> @@ -2285,13 +2309,12 @@\n>  \tchar *bufp;\n>  \tint nr, i;\n>  \n> -#define MSL_BIORQ_COMPLETE\t((void *)0x1)\n> -\n> -\tmemset(r, 0, sizeof(r));\n> -\n>  \tpsc_assert(mfh);\n>  \tpsc_assert(mfh->mfh_fcmh);\n>  \n> +\tif (!size)\n> +\t\treturn (0);\n> +\n>  \tf = mfh->mfh_fcmh;\n>  \n>  \tDEBUG_FCMH(PLL_INFO, f, \"buf=%p size=%zu off=%\"PRId64\" rw=%s\",\n> @@ -2316,12 +2339,21 @@\n>  \n>   restart:\n>  \trc = 0;\n> +\ttsize = size;\n>  \n> -\ttsize = size;\n>  \tFCMH_LOCK(f);\n> +\t/*\n> +\t * All I/O's block here for pending truncate requests.\n> +\t *\n> +\t * XXX there is a race here.  We should set CLI_TRUNC ourselves\n> +\t * until we are done setting up the I/O to block intervening\n> +\t * truncates.\n> +\t */\n> +\tfcmh_wait_locked(f, f->fcmh_flags & FCMH_CLI_TRUNC);\n> +\n>  \tfsz = fcmh_getsize(f);\n>  \n> -\tif (!size || (rw == SL_READ && off >= (off_t)fsz)) {\n> +\tif ((rw == SL_READ && off >= (off_t)fsz)) {\n>  \t\tFCMH_ULOCK(f);\n>  \t\tgoto out;\n>  \t}\n> @@ -2331,31 +2363,23 @@\n>  \tif ((rw == SL_READ) && ((tsize + off) > fsz))\n>  \t\ttsize = fsz - off;\n>  \n> -\t/*\n> -\t * All I/O's block here for pending truncate requests.\n> -\t *\n> -\t * XXX there is a race here.  We should set CLI_TRUNC ourselves\n> -\t * until we are done setting up the I/O to block intervening\n> -\t * truncates.\n> -\t */\n> -\tfcmh_wait_locked(f, f->fcmh_flags & FCMH_CLI_TRUNC);\n>  \tFCMH_ULOCK(f);\n>  \n>  \t/* Relativize the length and offset (roff is not aligned).\n>  \t */\n> -\troff  = off - (s * SLASH_BMAP_SIZE);\n> +\troff = off - (s * SLASH_BMAP_SIZE);\n>  \tpsc_assert(roff < SLASH_BMAP_SIZE);\n>  \n>  \t/* Length of the first bmap request.\n>  \t */\n> -\ttlen  = MIN(SLASH_BMAP_SIZE - (size_t)roff, tsize);\n> +\ttlen = MIN(SLASH_BMAP_SIZE - (size_t)roff, tsize);\n>  \n>  \t/*\n>  \t * Foreach block range, get its bmap and make a request into its\n>  \t *  page cache.  This first loop retrieves all the pages.\n>  \t */\n>  \tfor (i = 0, bufp = buf; i < nr; i++) {\n> -\t\tif (r[i])\n> +\t\tif (q->mfsrq_biorq[i])\n>  \t\t\tgoto load_next;\n>  \n>  \t\tDEBUG_FCMH(PLL_INFO, f, \"sz=%zu tlen=%zu off=%\"PSCPRIdOFFT\" \"\n> @@ -2384,36 +2408,39 @@\n>  \n>  \t\trc = msl_bmap_lease_tryext(b, NULL, 1);\n>  \t\tif (rc) {\n> -\t\t\tbmap_op_done_type(b, BMAP_OPCNT_LOOKUP);\n> +\t\t\tbmap_op_done(b);\n>  \t\t\tgoto retry_bmap;\n>  \t\t}\n>  \t\t/*\n>  \t\t * Re-relativize the offset if this request spans more\n>  \t\t * than 1 bmap.\n>  \t\t */\n> -\t\tmsl_biorq_build(&r[i], b, mfh, q,\n> -\t\t    roff - (i * SLASH_BMAP_SIZE), tlen,\n> -\t\t    (rw == SL_READ) ? BIORQ_READ : BIORQ_WRITE);\n> -\t\tbmap_op_done_type(b, BMAP_OPCNT_LOOKUP);\n> -\n> -\t\t/* Add the biorq to the fsrq. */\n> -\t\tmsl_fsrqinfo_biorq_add(q, r[i], i);\n> +\t\tmsl_biorq_build(q, b, bufp, i, roff - (i * SLASH_BMAP_SIZE), \n> +\t\t    tlen, (rw == SL_READ) ? BIORQ_READ : BIORQ_WRITE);\n> +\t\t\n> +\t\tbmap_op_done(b);\n>  \t\t/*\n>  \t\t * If we are not doing direct I/O, launch read for read\n>  \t\t * requests and pre-read for unaligned write requests.\n>  \t\t */\n> -\t\tif (!(r[i]->biorq_flags & BIORQ_DIO) &&\n> -\t\t    (r[i]->biorq_flags &\n> +\t\tr = q->mfsrq_biorq[i];\n> +\n> +\t\tif (!(r->biorq_flags & BIORQ_DIO) &&\n> +\t\t    (r->biorq_flags &\n>  \t\t      (BIORQ_READ | BIORQ_RBWFP | BIORQ_RBWLP))) {\n> -\t\t\trc = msl_pages_prefetch(r[i]);\n> +\t\t\trc = msl_pages_prefetch(r);\n>  \t\t\tif (rc) {\n> -\t\t\t\trc = msl_offline_retry(r[i]);\n> -\t\t\t\tr[i]->biorq_flags |= (r[i]->biorq_flags & BIORQ_READ) ?\n> +\t\t\t\trc = msl_offline_retry(r);\n> +\t\t\t\tr->biorq_flags |=\n> +\t\t\t\t\t(r->biorq_flags & BIORQ_READ) ?\n>  \t\t\t\t\tBIORQ_READFAIL : BIORQ_RBWFAIL;\n> -\t\t\t\tmsl_biorq_destroy(r[i]);\n> -\t\t\t\tr[i] = NULL;\n> +\n> +\t\t\t\tmsl_biorq_destroy(r);\n> +\t\t\t\tq->mfsrq_biorq[i] = NULL;\n> +\n>  \t\t\t\tif (rc)\n>  \t\t\t\t\tgoto retry_bmap;\n> +\n>  \t\t\t\trc = -EIO;\n>  \t\t\t\tgoto out;\n>  \t\t\t}\n> @@ -2430,27 +2457,29 @@\n>  \t * Note that the offsets used here are file-wise offsets not\n>  \t * offsets into the buffer.\n>  \t */\n> -\tfor (i = 0, tlen = 0, tsize = 0, bufp = buf;\n> -\t     i < nr; i++, bufp += tlen) {\n> -\t\tif (r[i] == MSL_BIORQ_COMPLETE)\n> +\tfor (i = 0, tlen = 0, tsize = 0; i < nr; i++) {\n> +\t\tr = q->mfsrq_biorq[i];\n> +\n> +\t\tif (r == MSL_BIORQ_COMPLETE)\n>  \t\t\tcontinue;\n>  \n>  \t\t/* Associate the biorq's with the mfh. */\n> -\t\tpll_addtail(&mfh->mfh_biorqs, r[i]);\n> +\t\tpll_addtail(&mfh->mfh_biorqs, r);\n>  \n> -\t\ttlen = r[i]->biorq_len;\n> +\t\ttlen = r->biorq_len;\n>  \n> -\t\tif (r[i]->biorq_flags & BIORQ_DIO) {\n> -\t\t\trc = msl_pages_dio_getput(r[i], bufp);\n> +\t\tif (r->biorq_flags & BIORQ_DIO) {\n> +\t\t\trc = msl_pages_dio_getput(r);\n>  \t\t\tif (rc == -SLERR_AIOWAIT) {\n>  \t\t\t\tmsl_fsrqinfo_aioset(q);\n> -\t\t\t\tgoto next_ioreq;\n> +\t\t\t\tcontinue;\n>  \t\t\t}\n>  \t\t\tif (rc) {\n> -\t\t\t\tpll_remove(&mfh->mfh_biorqs, r[i]);\n> -\t\t\t\trc = msl_offline_retry(r[i]);\n> +\t\t\t\tpll_remove(&mfh->mfh_biorqs, r);\n> +\t\t\t\trc = msl_offline_retry(r);\n>  \t\t\t\tif (rc) {\n> -\t\t\t\t\tr[i] = NULL;\n> +\t\t\t\t\tmsl_biorq_destroy(r);\n> +\t\t\t\t\tq->mfsrq_biorq[i] = NULL;\t\n>  \t\t\t\t\tgoto restart;\n>  \t\t\t\t}\n>  \t\t\t\trc = -EIO;\n> @@ -2461,14 +2490,14 @@\n>  \t\t\t *   other threads which may be working on pages\n>  \t\t\t *   which we need.\n>  \t\t\t */\n> -\t\t\trc = msl_pages_blocking_load(r[i]);\n> +\t\t\trc = msl_pages_blocking_load(r);\n>  \t\t\tif (rc == -SLERR_AIOWAIT) {\n> -\t\t\t\tDEBUG_BIORQ(PLL_INFO, r[i], \"SLERR_AIOWAIT\");\n> +\t\t\t\tDEBUG_BIORQ(PLL_INFO, r, \"SLERR_AIOWAIT\");\n>  \t\t\t\tmsl_fsrqinfo_aioset(q);\n> -\t\t\t\tgoto next_ioreq;\n> +\t\t\t\tcontinue;\n>  \t\t\t}\n>  \t\t\tif (rc) {\n> -\t\t\t\trc = msl_offline_retry(r[i]);\n> +\t\t\t\trc = msl_offline_retry(r);\n>  \t\t\t\tif (rc) {\n>  \t\t\t\t\t/*\n>  \t\t\t\t\t * The app wants to retry the\n> @@ -2483,14 +2512,16 @@\n>  \t\t\t\t\tif (bref)\n>  \t\t\t\t\t\tbmap_op_done_type(bref,\n>  \t\t\t\t\t\t    BMAP_OPCNT_BIORQ);\n> -\t\t\t\t\tbref = r[i]->biorq_bmap;\n> +\t\t\t\t\tbref = r->biorq_bmap;\n>  \t\t\t\t\tbmap_op_start_type(bref,\n>  \t\t\t\t\t    BMAP_OPCNT_BIORQ);\n>  \n> -\t\t\t\t\tr[i]->biorq_flags |= (r[i]->biorq_flags & BIORQ_READ) ?\n> +\t\t\t\t\tr->biorq_flags |= \n> +\t\t\t\t\t\t(r->biorq_flags & BIORQ_READ) ?\n>  \t\t\t\t\t\tBIORQ_READFAIL : BIORQ_RBWFAIL;\n> -\t\t\t\t\tmsl_biorq_destroy(r[i]);\n> -\t\t\t\t\tr[i] = NULL;\n> +\n> +\t\t\t\t\tmsl_biorq_destroy(r);\n> +\t\t\t\t\tq->mfsrq_biorq[i] = NULL;\n>  \t\t\t\t\tgoto restart;\n>  \t\t\t\t}\n>  \t\t\t\trc = -EIO;\n> @@ -2498,13 +2529,15 @@\n>  \t\t\t}\n>  \n>  \t\t\tif (rw == SL_READ)\n> -\t\t\t\ttlen = msl_pages_copyout(r[i], bufp);\n> +\t\t\t\ttlen = msl_pages_copyout(r);\n>  \t\t\telse\n> -\t\t\t\ttlen = msl_pages_copyin(r[i], bufp);\n> +\t\t\t\ttlen = msl_pages_copyin(r);\n>  \t\t}\n> +\n> +\t\t/* Not needed for AIO purposes.\n> +\t\t */\n> +\t\tq->mfsrq_biorq[i] = MSL_BIORQ_COMPLETE;\n>  \t\ttsize += tlen;\n> - next_ioreq:\n> -\t\tr[i] = MSL_BIORQ_COMPLETE;\n>  \t}\n>  \t/* Check for AIO in the fsrq prior to opening the fsrq for async\n>  \t *    operation.  Otherwise a race condition is possible where the\n> @@ -2518,18 +2551,22 @@\n>  \t\trc = tsize;\n>  \n>  \tmsl_fsrqinfo_readyset(q);\n> -\n>   out:\n>  \tif (bref)\n>  \t\tbmap_op_done_type(bref, BMAP_OPCNT_BIORQ);\n> -\n> +\t\n>  \t/* Note:  this is 'error' case.  For successful ops,\n>  \t *   msl_biorq_destroy called from msl_pages_copy[in|out].\n>  \t */\n> -\tfor (i = 0; i < nr; i++)\n> -\t\tif (r[i] && r[i] != MSL_BIORQ_COMPLETE) {\n> -\t\t\tr[i]->biorq_flags |= BIORQ_BMAPFAIL;\n> -\t\t\tmsl_biorq_destroy(r[i]);\n> +\tfor (i = 0; i < nr; i++) {\n> +\t\tr = q->mfsrq_biorq[i];\n> +\t\tpsc_assert(r);\n> +\n> +\t\tif (r != MSL_BIORQ_COMPLETE &&\n> +\t\t    !(r->biorq_flags & BIORQ_AIOWAIT)) {\n> +\t\t\tr->biorq_flags |= BIORQ_BMAPFAIL;\n> +\t\t\tmsl_biorq_destroy(r);\n>  \t\t}\n> +\t}\n>  \treturn (rc);\n>  }\n> Index: mount_slash/rci.c\n> ===================================================================\n> --- mount_slash/rci.c\t(revision 19009)\n> +++ mount_slash/rci.c\t(working copy)\n> @@ -155,7 +155,10 @@\n>  \t\t\tgoto error;\n>  \n>  \t\tif (mq->op == SRMIOP_RD) {\n> -\t\t\tiov.iov_base = car->car_argv.pointer_arg[MSL_CBARG_BUF];\n> +\t\t\tstruct bmpc_ioreq *r = \n> +\t\t\t\tcar->car_argv.pointer_arg[MSL_CBARG_BIORQ];\n> +\n> +\t\t\tiov.iov_base = r->biorq_buf;\n>  \t\t\tiov.iov_len = car->car_len;\n>  \n>  \t\t\tmq->rc = rsx_bulkserver(rq, BULK_GET_SINK,\n> @@ -164,8 +167,9 @@\n>  \t\t\tmsl_fsrqinfo_write(car->car_fsrqinfo);\n>  \t\t\treturn (0);\n>  \t\t}\n> -\t} else\n> +\t} else {\n>  \t\tpsc_fatalx(\"unknown callback\");\n> +\t}\n>  \t/*\n>  \t * The callback needs to be run even if the RPC failed so\n>  \t * cleanup can happen.\n> Index: mount_slash/rpc_cli.h\n> ===================================================================\n> --- mount_slash/rpc_cli.h\t(revision 19009)\n> +++ mount_slash/rpc_cli.h\t(working copy)\n> @@ -31,7 +31,6 @@\n>  /* async RPC pointers */\n>  #define MSL_CBARG_BMPCE\t\t\t0\n>  #define MSL_CBARG_CSVC\t\t\t1\n> -#define MSL_CBARG_BUF\t\t\t2\n>  #define MSL_CBARG_BIORQ\t\t\t3\n>  #define MSL_CBARG_BIORQS\t\t4\n>  #define MSL_CBARG_BMPC\t\t\t5\n> Index: mount_slash/bmpc.c\n> ===================================================================\n> --- mount_slash/bmpc.c\t(revision 19009)\n> +++ mount_slash/bmpc.c\t(working copy)\n> @@ -279,8 +279,8 @@\n>  \n>  \n>  struct bmpc_ioreq *\n> -bmpc_biorq_new(struct bmapc_memb *b, struct msl_fhent *f, \n> -       struct msl_fsrqinfo *q, uint32_t off, uint32_t len, int op)\n> +bmpc_biorq_new(struct msl_fsrqinfo *q, struct bmapc_memb *b, char *buf, \n> +    int rqnum, uint32_t off, uint32_t len, int op)\n>  {\n>  \tstruct bmpc_ioreq *r;\n>  \n> @@ -300,12 +300,16 @@\n>  \n>  \tr->biorq_off  = off;\n>  \tr->biorq_len  = len;\n> +\tr->biorq_buf = buf;\n>  \tr->biorq_bmap = b;\n>  \tr->biorq_flags = op;\n> -\tr->biorq_fhent = f;\n> +\tr->biorq_fhent = q->mfsrq_fh;\n>  \tr->biorq_fsrqi = q;\n>  \tr->biorq_last_sliod = IOS_ID_ANY;\n>  \n> +\t/* Add the biorq to the fsrq. */\n> +\tmsl_fsrqinfo_biorq_add(q, r, rqnum);\n> +\n>  \tbmap_op_start_type(b, BMAP_OPCNT_BIORQ);\n>  \n>  \tBMAP_LOCK(b);\n> Index: mount_slash/bmpc.h\n> ===================================================================\n> --- mount_slash/bmpc.h\t(revision 19009)\n> +++ mount_slash/bmpc.h\t(working copy)\n> @@ -240,6 +240,7 @@\n>  }\n>  \n>  struct bmpc_ioreq {\n> +\tchar                            *biorq_buf;\n>  \tuint32_t\t\t\t biorq_off;\t/* filewise, bmap relative\t*/\n>  \tuint32_t\t\t\t biorq_len;\t/* non-aligned, real length\t*/\n>  \tuint32_t\t\t\t biorq_flags;\t/* state and op type bits\t*/\n> @@ -433,8 +434,8 @@\n>  void  bmpc_freeall_locked(struct bmap_pagecache *);\n>  int   bmpc_biorq_cmp(const void *, const void *);\n>  void  bmpc_biorqs_fail(struct bmap_pagecache *, int);\n> -struct bmpc_ioreq *bmpc_biorq_new(struct bmapc_memb *, struct msl_fhent *, \n> -\t\t\t  struct msl_fsrqinfo *, uint32_t, uint32_t, int);\n> +struct bmpc_ioreq *bmpc_biorq_new(struct msl_fsrqinfo *, struct bmapc_memb *,\n> +    char *, int, uint32_t, uint32_t, int);\n>  int   bmpce_init(struct psc_poolmgr *, void *);\n>  void  bmpce_getbuf(struct bmap_pagecache_entry *);\n>  struct bmap_pagecache_entry *\n> Index: utils/typedump/typedump.c\n> ===================================================================\n> --- utils/typedump/typedump.c\t(revision 19009)\n> +++ utils/typedump/typedump.c\t(working copy)\n> @@ -47,6 +47,7 @@\n>  #include \"sltypes.h\"\n>  #include \"slutil.h\"\n>  #include \"mount_slash/bmap_cli.h\"\n> +#include \"mount_slash/bmapc_mem.h\"\n>  #include \"mount_slash/bmpc.h\"\n>  #include \"mount_slash/ctl_cli.h\"\n>  #include \"mount_slash/ctlsvr_cli.h\"\n> @@ -401,7 +402,6 @@\n>  \tPRVAL(MSL_CBARG_BMAP);\n>  \tPRVAL(MSL_CBARG_BMPC);\n>  \tPRVAL(MSL_CBARG_BMPCE);\n> -\tPRVAL(MSL_CBARG_BUF);\n>  \tPRVAL(MSL_CBARG_CSVC);\n>  \tPRVAL(MS_READAHEAD_MAXPGS);\n>  \tPRVAL(MS_READAHEAD_MINSEQ);\n> Index: sliod/slvr.c\n> ===================================================================\n> --- sliod/slvr.c\t(revision 19009)\n> +++ sliod/slvr.c\t(working copy)\n> @@ -338,6 +338,10 @@\n>  \tpscrpc_export_put(a->aiocbr_peer);\n>  \tif (csvc)\n>  \t\tsl_csvc_decref(csvc);\n> +\t/* Account for sli_aio_reply_setup()'s ref.\n> +\t */\n> +\tif (csvc)\n> +\t\tsl_csvc_decref(csvc);\n>  \n>  \tif (a->aiocbr_rw == SL_READ) {\n>  \t\tfor (i = 0; i < a->aiocbr_nslvrs; i++)\n> @@ -545,6 +549,9 @@\n>  \ta->aiocbr_len = len;\n>  \ta->aiocbr_off = off;\n>  \ta->aiocbr_rw = rw;\n> +\t/* Take a ref on the csvc.\n> +\t */\n> +\t(void *)sli_getclcsvc(rq->rq_export);\n>  \n>  \tspinlock(&a->aiocbr_lock);\n>  \ta->aiocbr_flags |= SLI_AIOCBSF_READY;\n```\nOn 2012-04-09 23:42:13 -0400, Paul Nowoczynski wrote:\n\n> ```\nThis should be the final patch.  It's in regression now and looking good.\n> \n> \n> Index: mount_slash/mount_slash.h\n> ===================================================================\n> --- mount_slash/mount_slash.h   (revision 19018)\n> +++ mount_slash/mount_slash.h   (working copy)\n> @@ -133,8 +133,10 @@\n>         int                              mra_bkwd;      /* reverse access io */\n>  };\n>  \n> -#define MAX_BMAPS_REQ                  4\n> +#define MAX_BMAPS_REQ                  2\n>  \n> +#define MSL_BIORQ_COMPLETE     ((void *)0x1)\n> +\n>  struct slc_async_req {\n>         struct psc_listentry              car_lentry;\n>         struct pscrpc_async_args          car_argv;\n> @@ -194,6 +196,7 @@\n>  \n>  void   msl_fsrqinfo_write(struct msl_fsrqinfo *);\n>  int    msl_fsrqinfo_state(struct msl_fsrqinfo *, int, int, int);\n> +void    msl_fsrqinfo_biorq_add(struct msl_fsrqinfo *, struct bmpc_ioreq *,int);\n>  \n>  #define msl_fsrqinfo_isset(q, f)       msl_fsrqinfo_state((q), (f), 0, 0)\n>  #define msl_fsrqinfo_aioisset(q)       msl_fsrqinfo_state((q), MFSRQ_AIOWAIT, 0, 0)\n> @@ -248,7 +251,7 @@\n>  int     msl_write_rpc_cb(struct pscrpc_request *, struct pscrpc_async_args *);\n>  int     msl_write_rpcset_cb(struct pscrpc_request_set *, void *, int);\n>  \n> -size_t  msl_pages_copyout(struct bmpc_ioreq *, char *);\n> +size_t  msl_pages_copyout(struct bmpc_ioreq *);\n>  \n>  struct slashrpc_cservice *\n>          msl_try_get_replica_res(struct bmapc_memb *, int);\n> Index: mount_slash/mount_slash_int.c\n> ===================================================================\n> --- mount_slash/mount_slash_int.c       (revision 19018)\n> +++ mount_slash/mount_slash_int.c       (working copy)\n> @@ -110,13 +110,13 @@\n>   * Notes: roff is bmap aligned.\n>   */\n>  __static void\n> -msl_biorq_build(struct bmpc_ioreq **newreq, struct bmapc_memb *b,\n> -       struct msl_fhent *mfh, struct msl_fsrqinfo *q, uint32_t roff,\n> -       uint32_t len, int op)\n> +msl_biorq_build(struct msl_fsrqinfo *q, struct bmapc_memb *b, char *buf,\n> +    int rqnum, uint32_t roff, uint32_t len, int op)\n>  {\n>         struct bmpc_ioreq *r;\n>         struct bmap_pagecache *bmpc;\n>         struct bmap_pagecache_entry *e, bmpce_search, *bmpce_new;\n> +       struct msl_fhent *mfh = q->mfsrq_fh;\n>         uint32_t aoff = (roff & ~BMPC_BUFMASK); /* aligned, relative offset */\n>         uint32_t alen = len + (roff & BMPC_BUFMASK);\n>         uint64_t foff = roff + bmap_foff(b); /* filewise offset */\n> @@ -136,7 +136,7 @@\n>  \n>         msl_update_iocounters(len);\n>  \n> -       *newreq = r = bmpc_biorq_new(b, mfh, q, roff, len, op);\n> +       r = bmpc_biorq_new(q, b, buf, rqnum, roff, len, op);\n>         if (r->biorq_flags & BIORQ_DIO)\n>                 /* The bmap is set to use directio, we may then skip\n>                  * cache preparation.\n> @@ -164,6 +164,7 @@\n>         }\n>  \n>         psc_assert(npages <= BMPC_IOMAXBLKS);\n> +\n>         if (op == BIORQ_WRITE)\n>                 maxpages = npages;\n>         else {\n> @@ -171,7 +172,7 @@\n>                  *    that could be acquired from this bmap.\n>                  */\n>                 int rapages;\n> -\n> +               \n>                 /* First, query the read ahead struct in the mfh to\n>                  *   obtain rapages and ra direction.\n>                  */\n> @@ -182,30 +183,29 @@\n>                         psc_assert(bkwdra == 0 || bkwdra == 1);\n>                         n = bkwdra ? (aoff / BMPC_BLKSZ) :\n>                                 (SLASH_BMAP_SIZE - aoff) / BMPC_BLKSZ;\n> -\n> -                       /* Read ahead must be contained within this bmap.\n> +                       /* Read ahead must be contained within this bmap\n>                          */\n>                         maxpages = MIN(rapages, n);\n>                         if (!bkwdra) {\n>                                 /* Don't prefetch past EOF\n>                                  */\n>                                 n = ((fsz - (bmap_foff(b) + roff)) /\n> -                                    BMPC_BLKSZ) +\n> +                                   BMPC_BLKSZ) +\n>                                         ((fsz % BMPC_BLKSZ) ? 1 : 0);\n>  \n>                                 maxpages = MIN(maxpages, n);\n>                         }\n>                         if (maxpages < npages)\n>                                 maxpages = npages;\n> -\n> +                       \n>                         DEBUG_BMAP(PLL_INFO, b, \"maxpages=%d npages=%d \"\n> -                          \"bkwdra=%d\", maxpages, npages, bkwdra);\n> +                           \"bkwdra=%d\", maxpages, npages, bkwdra);\n>                 } else {\n>                         maxpages = npages;\n>                         bkwdra = 0;\n>                 }\n>         }\n> -\n> +       \n>         /* Lock the bmap's page cache and try to locate cached pages\n>          *   which correspond to this request.\n>          */\n> @@ -839,16 +839,15 @@\n>  msl_fsrq_complete(struct msl_fsrqinfo *q)\n>  {\n>         struct bmpc_ioreq *r;\n> -       size_t len, rc;\n> -       char *buf = q->mfsrq_buf;\n> +       size_t len = 0, rc;\n>         int i;\n>  \n>         psc_assert(!q->mfsrq_ref);\n>  \n>         for (i = 0, len = 0; i < MAX_BMAPS_REQ; i++) {\n>                 r = q->mfsrq_biorq[i];\n> -               if (!r)\n> -                       break;\n> +               if (!r || r == MSL_BIORQ_COMPLETE)\n> +                       continue;\n>  \n>                 BIORQ_LOCK(r);\n>                 r->biorq_flags &= ~(BIORQ_INFL | BIORQ_SCHED);\n> @@ -856,27 +855,42 @@\n>                 BIORQ_ULOCK(r);\n>  \n>                 DEBUG_BIORQ(PLL_INFO, r, \"fsrq_complete\");\n> -               if (q->mfsrq_err)\n> +\n> +               /* Aio writes are handled server side.\n> +                */\n> +               if (q->mfsrq_rw != SL_READ)\n> +                       abort();\n> +\n> +               psc_assert(r->biorq_flags & BIORQ_READ);\n> +               \n> +               if (q->mfsrq_err) {\n>                         msl_biorq_destroy(r);\n> +                       continue;\n> +               }\n>  \n> -               else if (q->mfsrq_rw == SL_READ) {\n> -                       psc_assert(r->biorq_flags & BIORQ_READ);\n> +               if (i && !len)\n> +                       /* This fsrq has 2 biorqs (probably spanned 2 bmaps)\n> +                        * and the first biorq was completed via cache so\n> +                        * interpolate its len.\n> +                        */\n> +                       len = q->mfsrq_size - r->biorq_len;\n> +\n> +               if (r->biorq_flags & BIORQ_DIO) {\n>                         /* Support mix of dio and cached reads.  This may occur\n> -                        *   if the read request spans bmaps.\n> +                        * if the read request spans bmaps.  The 'len' here was\n> +                        * possibly adjusted against the tail of the file in\n> +                        * msl_io.\n>                          */\n> -                       if (r->biorq_flags & BIORQ_DIO) {\n> -                               len += r->biorq_len;\n> -                               msl_biorq_destroy(r);\n> -                       } else {\n> -                               rc = msl_pages_copyout(r, buf);\n> -                               if (!rc)\n> -                                       break;\n> -                               len += rc;\n> -                       }\n> -                       buf += len;\n> +                       len += r->biorq_len;\n> +                       msl_biorq_destroy(r);\n> +\n> +               } else {\n> +                       rc = msl_pages_copyout(r);\n> +                       if (!rc)\n> +                               break;\n> +                       len += rc;\n>                         psc_assert(len <= q->mfsrq_size);\n> -               } else\n> -                       abort();\n> +               }\n>         }\n>  \n>         if (!q->mfsrq_err) {\n> @@ -903,9 +917,14 @@\n>          */\n>         for (i = 0; i < MAX_BMAPS_REQ; i++) {\n>                 r = q->mfsrq_biorq[i];\n> -               if (!r)\n> +               if (!r) {\n> +                       psc_assert(i);\n>                         break;\n> +               }\n>  \n> +               if (r == MSL_BIORQ_COMPLETE)\n> +                       continue;\n> +\n>                 psc_assert(r->biorq_flags & BIORQ_AIOWAIT);\n>  \n>                 DYNARRAY_FOREACH(e, j, &r->biorq_pages) {\n> @@ -946,11 +965,14 @@\n>         struct psc_dynarray a = DYNARRAY_INIT;\n>         int i;\n>  \n> +       /* If fsrq cannot be completed. msl_fsrq_completion_try()\n> +        * will reattach it to another aio'd bmpce.\n> +        */\n>         while ((q = pll_get(&e->bmpce_pndgaios)))\n> +               /* msl_fsrq_completion_try() may remove 'e' so loop\n> +                * gather work before calling msl_fsrq_completion_try().\n> +                */\n>                 psc_dynarray_add(&a, q);\n> -               /* If fsrq cannot be completed. msl_fsrq_completion_try()\n> -                *   will reattach it to another aio'd bmpce.\n> -                */\n>  \n>         DYNARRAY_FOREACH(q, i, &a) {\n>                 msl_fsrq_completion_try(q);\n> @@ -1247,7 +1269,7 @@\n>  }\n>  \n>  __static int\n> -msl_pages_dio_getput(struct bmpc_ioreq *r, char *bufp)\n> +msl_pages_dio_getput(struct bmpc_ioreq *r)\n>  {\n>         struct slashrpc_cservice  *csvc = NULL;\n>         struct pscrpc_request     *rq = NULL;\n> @@ -1297,8 +1319,7 @@\n>                 rq->rq_interpret_reply = msl_dio_cb0;\n>                 rq->rq_async_args.pointer_arg[MSL_CBARG_CSVC] = csvc;\n>                 rq->rq_async_args.pointer_arg[MSL_CBARG_BIORQ] = r;\n> -               rq->rq_async_args.pointer_arg[MSL_CBARG_BUF] = bufp + nbytes;\n> -               iovs[i].iov_base = bufp + nbytes;\n> +               iovs[i].iov_base = r->biorq_buf + nbytes;\n>                 iovs[i].iov_len  = len;\n>  \n>                 rc = rsx_bulkclient(rq, (op == SRMT_WRITE ?\n> @@ -1337,9 +1358,9 @@\n>         switch (rc) {\n>         case 0:\n>                 psc_iostats_intv_add((op == SRMT_WRITE ?\n> -                                     &msl_diowr_stat : &msl_diord_stat), size);\n> +                       &msl_diowr_stat : &msl_diord_stat), size);\n>  \n> -               msl_biorq_destroy(r);           \n> +               msl_biorq_destroy(r);\n>                 break;\n>  \n>         case -SLERR_AIOWAIT:\n> @@ -1893,16 +1914,16 @@\n>   * @buf: the source (application) buffer.\n>   */\n>  __static size_t\n> -msl_pages_copyin(struct bmpc_ioreq *r, char *buf)\n> +msl_pages_copyin(struct bmpc_ioreq *r)\n>  {\n>         struct bmap_pagecache_entry *e;\n>         uint32_t toff, tsize, nbytes;\n>         char *dest, *src;\n>         int i;\n>  \n> -       src    = buf;\n> -       tsize  = r->biorq_len;\n> -       toff   = r->biorq_off;\n> +       src = r->biorq_buf;\n> +       tsize = r->biorq_len;\n> +       toff = r->biorq_off;\n>         DYNARRAY_FOREACH(e, i, &r->biorq_pages) {\n>                 /* All pages are involved, therefore tsize should have value.\n> @@ -1977,7 +1998,7 @@\n>   * msl_pages_copyout - Copy pages to the user application buffer.\n>   */\n>  size_t\n> -msl_pages_copyout(struct bmpc_ioreq *r, char *buf)\n> +msl_pages_copyout(struct bmpc_ioreq *r)\n>  {\n>         struct bmap_pagecache_entry *e;\n>         size_t nbytes, tbytes=0, rflen;\n> @@ -1985,10 +2006,10 @@\n>         char *dest, *src;\n>         off_t toff;\n>  \n> -       dest   = buf;\n> -       toff   = r->biorq_off;\n> +       dest = r->biorq_buf;\n> +       toff = r->biorq_off;\n>  \n> -       rflen  = fcmh_getsize(r->biorq_bmap->bcm_fcmh) -\n> +       rflen = fcmh_getsize(r->biorq_bmap->bcm_fcmh) -\n>                 bmap_foff(r->biorq_bmap);\n>  \n>         if (biorq_voff_get(r) > rflen) {\n> @@ -2203,13 +2224,16 @@\n>         pscfs_reply_write(q->mfsrq_pfr, q->mfsrq_size, rc);\n>  }\n>  \n> -__static void\n> -msl_fsrqinfo_biorq_add(struct msl_fsrqinfo *q, struct bmpc_ioreq *r,\n> -    int pos)\n> +void\n> +msl_fsrqinfo_biorq_add(struct msl_fsrqinfo *q, struct bmpc_ioreq *r, \n> +    int biorq_num)\n>  {\n> +       psc_assert(q->mfsrq_fh == r->biorq_fhent);\n> +\n>         MFH_LOCK(r->biorq_fhent);\n> -       DEBUG_BIORQ(PLL_INFO, r, \"q=%p pos=%d\", q, pos);\n> -       q->mfsrq_biorq[pos] = r;\n> +       DEBUG_BIORQ(PLL_INFO, r, \"q=%p pos=%d\", q, biorq_num);\n> +       psc_assert(!q->mfsrq_biorq[biorq_num]);\n> +       q->mfsrq_biorq[biorq_num] = r;\n>         MFH_ULOCK(r->biorq_fhent);\n>  }\n>  \n> @@ -2236,6 +2260,8 @@\n>                 int i;\n>  \n>                 /* The fs request was reissued.  Clear out any old state.\n> +                * Yes, this can happen by the magic (or insanity) that is\n> +                * async IO and slc_rci_handle_io().\n>                  */\n>                 psc_assert(q->mfsrq_fh == mfh &&\n>                            q->mfsrq_buf == buf &&\n> @@ -2246,9 +2272,10 @@\n>  \n>                 for (i = 0; i < MAX_BMAPS_REQ; i++) {\n>                         if (!q->mfsrq_biorq[i])\n> -                               break;\n> +                               continue;\n>  \n>                         msl_biorq_destroy(q->mfsrq_biorq[i]);\n> +                       q->mfsrq_biorq[i] = NULL;\n>                 }\n>         }\n>         return (q);\n> @@ -2274,10 +2301,10 @@\n>  msl_io(struct pscfs_req *pfr, struct msl_fhent *mfh, char *buf,\n>      const size_t size, const off_t off, enum rw rw)\n>  {\n> -       struct bmpc_ioreq *r[MAX_BMAPS_REQ];\n>         struct bmapc_memb *b, *bref = NULL;\n>         struct fidc_membh *f;\n>         struct msl_fsrqinfo *q;\n> +       struct bmpc_ioreq *r;\n>         size_t s, e, tlen, tsize;\n>         uint64_t fsz;\n>         ssize_t rc;\n> @@ -2285,13 +2312,12 @@\n>  \n>   restart:\n>         rc = 0;\n> +       tsize = size;\n>  \n> -       tsize = size;\n>         FCMH_LOCK(f);\n> +       /*\n> +        * All I/O's block here for pending truncate requests.\n> +        *\n> +        * XXX there is a race here.  We should set CLI_TRUNC ourselves\n> +        * until we are done setting up the I/O to block intervening\n> +        * truncates.\n> +        */\n> +       fcmh_wait_locked(f, f->fcmh_flags & FCMH_CLI_TRUNC);\n> +\n>         fsz = fcmh_getsize(f);\n>  \n> -       if (!size || (rw == SL_READ && off >= (off_t)fsz)) {\n> +       if ((rw == SL_READ && off >= (off_t)fsz)) {\n>                 FCMH_ULOCK(f);\n>                 goto out;\n>         }\n> @@ -2331,31 +2366,23 @@\n>         if ((rw == SL_READ) && ((tsize + off) > fsz))\n>                 tsize = fsz - off;\n>  \n> -       /*\n> -        * All I/O's block here for pending truncate requests.\n> -        *\n> -        * XXX there is a race here.  We should set CLI_TRUNC ourselves\n> -        * until we are done setting up the I/O to block intervening\n> -        * truncates.\n> -        */\n> -       fcmh_wait_locked(f, f->fcmh_flags & FCMH_CLI_TRUNC);\n>         FCMH_ULOCK(f);\n>  \n>         /* Relativize the length and offset (roff is not aligned).\n>          */\n> -       roff  = off - (s * SLASH_BMAP_SIZE);\n> +       roff = off - (s * SLASH_BMAP_SIZE);\n>         psc_assert(roff < SLASH_BMAP_SIZE);\n>  \n>         /* Length of the first bmap request.\n>          */\n> -       tlen  = MIN(SLASH_BMAP_SIZE - (size_t)roff, tsize);\n> +       tlen = MIN(SLASH_BMAP_SIZE - (size_t)roff, tsize);\n>  \n>         /*\n>          * Foreach block range, get its bmap and make a request into its\n>          *  page cache.  This first loop retrieves all the pages.\n>          */\n>         for (i = 0, bufp = buf; i < nr; i++) {\n> -               if (r[i])\n> +               if (q->mfsrq_biorq[i])\n>                         goto load_next;\n>  \n>                 DEBUG_FCMH(PLL_INFO, f, \"sz=%zu tlen=%zu off=%\"PSCPRIdOFFT\" \"\n> @@ -2384,36 +2411,39 @@\n>  \n>                 rc = msl_bmap_lease_tryext(b, NULL, 1);\n>                 if (rc) {\n> -                       bmap_op_done_type(b, BMAP_OPCNT_LOOKUP);\n> +                       bmap_op_done(b);\n>                         goto retry_bmap;\n>                 }\n>                 /*\n>                  * Re-relativize the offset if this request spans more\n>                  * than 1 bmap.\n>                  */\n> -               msl_biorq_build(&r[i], b, mfh, q,\n> -                   roff - (i * SLASH_BMAP_SIZE), tlen,\n> -                   (rw == SL_READ) ? BIORQ_READ : BIORQ_WRITE);\n> -               bmap_op_done_type(b, BMAP_OPCNT_LOOKUP);\n> -\n> -               /* Add the biorq to the fsrq. */\n> -               msl_fsrqinfo_biorq_add(q, r[i], i);\n> +               msl_biorq_build(q, b, bufp, i, roff - (i * SLASH_BMAP_SIZE), \n> +                   tlen, (rw == SL_READ) ? BIORQ_READ : BIORQ_WRITE);\n> +               \n> +               bmap_op_done(b);\n>                 /*\n>                  * If we are not doing direct I/O, launch read for read\n>                  * requests and pre-read for unaligned write requests.\n>                  */\n> -               if (!(r[i]->biorq_flags & BIORQ_DIO) &&\n> -                   (r[i]->biorq_flags &\n> +               r = q->mfsrq_biorq[i];\n> +\n> +               if (!(r->biorq_flags & BIORQ_DIO) &&\n> +                   (r->biorq_flags &\n>                       (BIORQ_READ | BIORQ_RBWFP | BIORQ_RBWLP))) {\n> -                       rc = msl_pages_prefetch(r[i]);\n> +                       rc = msl_pages_prefetch(r);\n>                         if (rc) {\n> -                               rc = msl_offline_retry(r[i]);\n> -                               r[i]->biorq_flags |= (r[i]->biorq_flags & BIORQ_READ) ?\n> +                               rc = msl_offline_retry(r);\n> +                               r->biorq_flags |=\n> +                                       (r->biorq_flags & BIORQ_READ) ?\n>                                         BIORQ_READFAIL : BIORQ_RBWFAIL;\n> -                               msl_biorq_destroy(r[i]);\n> -                               r[i] = NULL;\n> +\n> +                               msl_biorq_destroy(r);\n> +                               q->mfsrq_biorq[i] = NULL;\n> +\n>                                 if (rc)\n>                                         goto retry_bmap;\n> +\n>                                 rc = -EIO;\n>                                 goto out;\n>                         }\n> @@ -2430,27 +2460,29 @@\n>          * Note that the offsets used here are file-wise offsets not\n>          * offsets into the buffer.\n>          */\n> -       for (i = 0, tlen = 0, tsize = 0, bufp = buf;\n> -            i < nr; i++, bufp += tlen) {\n> -               if (r[i] == MSL_BIORQ_COMPLETE)\n> +       for (i = 0, tlen = 0, tsize = 0; i < nr; i++) {\n> +               r = q->mfsrq_biorq[i];\n> +\n> +               if (r == MSL_BIORQ_COMPLETE)\n>                         continue;\n>  \n>                 /* Associate the biorq's with the mfh. */\n> -               pll_addtail(&mfh->mfh_biorqs, r[i]);\n> +               pll_addtail(&mfh->mfh_biorqs, r);\n>  \n> -               tlen = r[i]->biorq_len;\n> +               tlen = r->biorq_len;\n>  \n> -               if (r[i]->biorq_flags & BIORQ_DIO) {\n> -                       rc = msl_pages_dio_getput(r[i], bufp);\n> +               if (r->biorq_flags & BIORQ_DIO) {\n> +                       rc = msl_pages_dio_getput(r);\n>                         if (rc == -SLERR_AIOWAIT) {\n>                                 msl_fsrqinfo_aioset(q);\n> -                               goto next_ioreq;\n> +                               continue;\n>                         }\n>                         if (rc) {\n> -                               pll_remove(&mfh->mfh_biorqs, r[i]);\n> -                               rc = msl_offline_retry(r[i]);\n> +                               pll_remove(&mfh->mfh_biorqs, r);\n> +                               rc = msl_offline_retry(r);\n>                                 if (rc) {\n> -                                       r[i] = NULL;\n> +                                       msl_biorq_destroy(r);\n> +                                       q->mfsrq_biorq[i] = NULL;       \n>                                         goto restart;\n>                                 }\n>                                 rc = -EIO;\n> @@ -2461,14 +2493,14 @@\n>                          *   other threads which may be working on pages\n>                          *   which we need.\n>                          */\n> -                       rc = msl_pages_blocking_load(r[i]);\n> +                       rc = msl_pages_blocking_load(r);\n>                         if (rc == -SLERR_AIOWAIT) {\n> -                               DEBUG_BIORQ(PLL_INFO, r[i], \"SLERR_AIOWAIT\");\n> +                               DEBUG_BIORQ(PLL_INFO, r, \"SLERR_AIOWAIT\");\n>                                 msl_fsrqinfo_aioset(q);\n> -                               goto next_ioreq;\n> +                               continue;\n>                         }\n>                         if (rc) {\n> -                               rc = msl_offline_retry(r[i]);\n> +                               rc = msl_offline_retry(r);\n>                                 if (rc) {\n>                                         /*\n>                                          * The app wants to retry the\n> @@ -2483,14 +2515,16 @@\n>                                         if (bref)\n>                                                 bmap_op_done_type(bref,\n>                                                     BMAP_OPCNT_BIORQ);\n> -                                       bref = r[i]->biorq_bmap;\n> +                                       bref = r->biorq_bmap;\n>                                         bmap_op_start_type(bref,\n>                                             BMAP_OPCNT_BIORQ);\n>  \n> -                                       r[i]->biorq_flags |= (r[i]->biorq_flags & BIORQ_READ) ?\n> +                                       r->biorq_flags |= \n> +                                               (r->biorq_flags & BIORQ_READ) ?\n>                                                 BIORQ_READFAIL : BIORQ_RBWFAIL;\n> -                                       msl_biorq_destroy(r[i]);\n> -                                       r[i] = NULL;\n> +\n> +                                       msl_biorq_destroy(r);\n> +                                       q->mfsrq_biorq[i] = NULL;\n>                                         goto restart;\n>                                 }\n>                                 rc = -EIO;\n> @@ -2498,13 +2532,15 @@\n>                         }\n>  \n>                         if (rw == SL_READ)\n> -                               tlen = msl_pages_copyout(r[i], bufp);\n> +                               tlen = msl_pages_copyout(r);\n>                         else\n> -                               tlen = msl_pages_copyin(r[i], bufp);\n> +                               tlen = msl_pages_copyin(r);\n>                 }\n> +\n> +               /* Not needed for AIO purposes.\n> +                */\n> +               q->mfsrq_biorq[i] = MSL_BIORQ_COMPLETE;\n>                 tsize += tlen;\n> - next_ioreq:\n> -               r[i] = MSL_BIORQ_COMPLETE;\n>         }\n>         /* Check for AIO in the fsrq prior to opening the fsrq for async\n>          *    operation.  Otherwise a race condition is possible where the\n> @@ -2518,18 +2554,21 @@\n>                 rc = tsize;\n>  \n>         msl_fsrqinfo_readyset(q);\n> -\n>   out:\n>         if (bref)\n>                 bmap_op_done_type(bref, BMAP_OPCNT_BIORQ);\n> -\n> +       \n>         /* Note:  this is 'error' case.  For successful ops,\n>          *   msl_biorq_destroy called from msl_pages_copy[in|out].\n>          */\n> -       for (i = 0; i < nr; i++)\n> -               if (r[i] && r[i] != MSL_BIORQ_COMPLETE) {\n> -                       r[i]->biorq_flags |= BIORQ_BMAPFAIL;\n> -                       msl_biorq_destroy(r[i]);\n> +       for (i = 0; i < nr; i++) {\n> +               r = q->mfsrq_biorq[i];\n> +\n> +               if (r && r != MSL_BIORQ_COMPLETE &&\n> +                   !(r->biorq_flags & BIORQ_AIOWAIT)) {\n> +                       r->biorq_flags |= BIORQ_BMAPFAIL;\n> +                       msl_biorq_destroy(r);\n>                 }\n> +       }\n>         return (rc);\n>  }\n> Index: mount_slash/bmap_cli.c\n> ===================================================================\n> --- mount_slash/bmap_cli.c      (revision 19018)\n> +++ mount_slash/bmap_cli.c      (working copy)\n> @@ -220,15 +220,20 @@\n>                  *   bmap out of the fid cache so that others don't stumble\n>                  *   across it while it's active I/O's are failed.\n>                  */\n> -               if (b->bcm_flags & BMAP_CLI_LEASEEXPIRED)\n> +               if (b->bcm_flags & BMAP_CLI_LEASEEXPIRED) {\n>                         psc_assert(b->bcm_flags & BMAP_ORPHAN);\n> -               else {\n> +\n> +               } else {\n>                         /* Note:  bmap_orphan() will drop the bmap lock\n>                          *   so it's important that BMAP_CLI_LEASEEXPIRED\n>                          *   is set afterwards so that it is atomic with\n>                          *   bmpc_biorqs_fail().\n>                          */\n> -                       bmap_orphan(b);\n> +                       if (b->bcm_flags & BMAP_ORPHAN)\n> +                               DEBUG_BMAP(PLL_WARN, b, \"already orphaned\");\n> +                       else \n> +                               bmap_orphan(b);\n> +\n>                         BMAP_SETATTR(b, BMAP_CLI_LEASEEXPIRED);\n>                         bmpc_biorqs_fail(bmap_2_bmpc(b),\n>                                  BIORQ_EXPIREDLEASE);\n> @@ -397,11 +402,15 @@\n>                         }\n>                 } // else NOOP\n>  \n> -       } else if (secs > BMAP_CLI_EXTREQSECS)\n> +       } else if (b->bcm_flags & BMAP_ORPHAN) {\n> +               DEBUG_BMAP(PLL_WARN, b,\n> +                  \"not requesting extension for orphaned bmap\");\n> +\n> +       } else if (secs > BMAP_CLI_EXTREQSECS) {\n>                 timespecadd(&ts, &msl_bmap_timeo_inc,\n>                     &bmap_2_bci(b)->bci_etime);\n>  \n> -       else {\n> +       } else {\n>                 struct slashrpc_cservice *csvc = NULL;\n>                 struct pscrpc_request *rq = NULL;\n>                 struct srm_leasebmapext_req *mq;\n> @@ -440,6 +449,8 @@\n>                                 pscrpc_req_finished(rq);\n>                         if (csvc)\n>                                 sl_csvc_decref(csvc);\n> +\n> +                       bmap_op_done_type(b, BMAP_OPCNT_LEASEEXT);\n>                 }\n>                 DEBUG_BMAP(rc ? PLL_ERROR : PLL_NOTIFY, b,\n>                            \"lease extension req (rc=%d) (secs=%d)\", rc, secs);\n> Index: mount_slash/rci.c\n> ===================================================================\n> --- mount_slash/rci.c   (revision 19018)\n> +++ mount_slash/rci.c   (working copy)\n> @@ -155,7 +155,10 @@\n>                         goto error;\n>  \n>                 if (mq->op == SRMIOP_RD) {\n> -                       iov.iov_base = car->car_argv.pointer_arg[MSL_CBARG_BUF];\n> +                       struct bmpc_ioreq *r = \n> +                               car->car_argv.pointer_arg[MSL_CBARG_BIORQ];\n> +\n> +                       iov.iov_base = r->biorq_buf;\n>                         iov.iov_len = car->car_len;\n>  \n>                         mq->rc = rsx_bulkserver(rq, BULK_GET_SINK,\n> @@ -164,8 +167,9 @@\n>                         msl_fsrqinfo_write(car->car_fsrqinfo);\n>                         return (0);\n>                 }\n> -       } else\n> +       } else {\n>                 psc_fatalx(\"unknown callback\");\n> +       }\n>         /*\n>          * The callback needs to be run even if the RPC failed so\n>          * cleanup can happen.\n> Index: mount_slash/rpc_cli.h\n> ===================================================================\n> --- mount_slash/rpc_cli.h       (revision 19018)\n> +++ mount_slash/rpc_cli.h       (working copy)\n> @@ -31,7 +31,6 @@\n>  /* async RPC pointers */\n>  #define MSL_CBARG_BMPCE                        0\n>  #define MSL_CBARG_CSVC                 1\n> -#define MSL_CBARG_BUF                  2\n>  #define MSL_CBARG_BIORQ                        3\n>  #define MSL_CBARG_BIORQS               4\n>  #define MSL_CBARG_BMPC                 5\n> Index: mount_slash/bmpc.c\n> ===================================================================\n> --- mount_slash/bmpc.c  (revision 19018)\n> +++ mount_slash/bmpc.c  (working copy)\n> @@ -279,8 +279,8 @@\n>  \n>  \n>  struct bmpc_ioreq *\n> -bmpc_biorq_new(struct bmapc_memb *b, struct msl_fhent *f, \n> -       struct msl_fsrqinfo *q, uint32_t off, uint32_t len, int op)\n> +bmpc_biorq_new(struct msl_fsrqinfo *q, struct bmapc_memb *b, char *buf, \n> +    int rqnum, uint32_t off, uint32_t len, int op)\n>  {\n>         struct bmpc_ioreq *r;\n>  \n> @@ -300,12 +300,16 @@\n>  \n>         r->biorq_off  = off;\n>         r->biorq_len  = len;\n> +       r->biorq_buf = buf;\n>         r->biorq_bmap = b;\n>         r->biorq_flags = op;\n> -       r->biorq_fhent = f;\n> +       r->biorq_fhent = q->mfsrq_fh;\n>         r->biorq_fsrqi = q;\n>         r->biorq_last_sliod = IOS_ID_ANY;\n>  \n> +       /* Add the biorq to the fsrq. */\n> +       msl_fsrqinfo_biorq_add(q, r, rqnum);\n> +\n>         bmap_op_start_type(b, BMAP_OPCNT_BIORQ);\n>  \n>         BMAP_LOCK(b);\n> Index: mount_slash/bmpc.h\n> ===================================================================\n> --- mount_slash/bmpc.h  (revision 19018)\n> +++ mount_slash/bmpc.h  (working copy)\n> @@ -240,6 +240,7 @@\n>  }\n>  \n>  struct bmpc_ioreq {\n> +       char                            *biorq_buf;\n>         uint32_t                         biorq_off;     /* filewise, bmap relative      */\n>         uint32_t                         biorq_len;     /* non-aligned, real length     */\n>         uint32_t                         biorq_flags;   /* state and op type bits       */\n> @@ -433,8 +434,8 @@\n>  void  bmpc_freeall_locked(struct bmap_pagecache *);\n>  int   bmpc_biorq_cmp(const void *, const void *);\n>  void  bmpc_biorqs_fail(struct bmap_pagecache *, int);\n> -struct bmpc_ioreq *bmpc_biorq_new(struct bmapc_memb *, struct msl_fhent *, \n> -                         struct msl_fsrqinfo *, uint32_t, uint32_t, int);\n> +struct bmpc_ioreq *bmpc_biorq_new(struct msl_fsrqinfo *, struct bmapc_memb *,\n> +    char *, int, uint32_t, uint32_t, int);\n>  int   bmpce_init(struct psc_poolmgr *, void *);\n>  void  bmpce_getbuf(struct bmap_pagecache_entry *);\n>  struct bmap_pagecache_entry *\n```\nOn 2012-05-29 15:55:37 -0400, Paul Nowoczynski wrote:\n\n> ```\nr19076 should have fixed this and a number of other AIO bugs.\n```\n"}}