// 7.1.219 : Pass context token to different process & do detach/release.
int test_detach_diff_proc()
{
    int rc=0;
    int cstat;
    struct ctx myctx;
    struct ctx *p_ctx = &myctx;

    pid = getpid();

    //ctx_init with default flash disk & devno
    rc = ctx_init(p_ctx);
    CHECK_RC(rc, "Context init failed");

    rc = fork();
    if ( rc == -1 ) CHECK_RC(1, "fork() failed");

    // child process
    if ( rc == 0 )
    {
        pid = getpid();

        rc = ctx_close(p_ctx);
        if ( 22 != rc )
            CHECK_RC_EXIT(1, "Context detach did not fail");

        exit(0);
    }
    else
    {
        // Probe child's exit status.
        if ( wait(&cstat) == -1 )
            CHECK_RC(1, "Failed while wait() for child");

        // We expect child to exit itself
        if (WIFEXITED(cstat))
        {
            // We expect child to exit with rc 0 only !
            if ( WEXITSTATUS(cstat) != 0 ) rc=1;
            else rc=0;
        }
    }

    rc |= ctx_close(p_ctx);

    return rc;
}
int test_clone_ioctl(int cmd)
{
    struct ctx myctx;
    int i;
    pid_t cpid;
    struct ctx *p_ctx=&myctx;
    uint64_t nlba;
    uint64_t st_lba;
    uint64_t stride=0x1000;
    int rc=0;
    uint64_t src_ctx_id;
    uint64_t src_adap_fd;
    pthread_t thread;
    uint64_t resource[MAX_RES_HANDLE];
    uint64_t RES_CLOSED=-1;
    int cl_index[5]={ 1,7,10,12,15 };
    pid = getpid();
    rc =ctx_init(p_ctx);
    CHECK_RC(rc, "Context init failed");
    pthread_create(&thread, NULL, ctx_rrq_rx, p_ctx);
    p_ctx->flags = DK_UVF_ALL_PATHS;
    for (i=0;i<MAX_RES_HANDLE;i++)
    {
        p_ctx->lun_size = (i+1)*p_ctx->chunk_size;
        rc = create_res(p_ctx);
        CHECK_RC(rc, "create res failed");
        resource[i]=p_ctx->rsrc_handle;
    }
    for (i=0;i<5;i++)
    {
        p_ctx->rsrc_handle= resource[cl_index[i]];
        close_res(p_ctx);
        resource[cl_index[i]]= RES_CLOSED;
    }
    for (i=0; i<MAX_RES_HANDLE;i++)
    {
        if (RES_CLOSED == resource[i])
            continue;
        nlba = (i+1)*p_ctx->chunk_size;
        p_ctx->rsrc_handle = resource[i];
        p_ctx->res_hndl = p_ctx->rsrc_handle & RES_HNDLR_MASK;
        for (st_lba=0;st_lba<nlba;st_lba += (NUM_CMDS*stride))
        {
            rc = send_write(p_ctx,st_lba,stride,pid);
            CHECK_RC(rc, "send write failed\n");
        }
    }
    //write done cancel thread now
    pthread_cancel(thread);
    cpid = fork();
    if (cpid == 0)
    {
        //child process
        pid = getpid();
        ppid = getppid();
        //take backup parent ctx_id
        src_ctx_id= p_ctx->context_id;
        src_adap_fd = p_ctx->adap_fd;
        //do unmap parent mmio 1st
        rc =munmap((void *)p_ctx->p_host_map, p_ctx->mmio_size);
        CHECK_RC_EXIT(rc, "munmap failed\n");
        //do fresh attach for child
        rc = ctx_init_internal(p_ctx,DK_AF_ASSIGN_AFU,p_ctx->devno);
        CHECK_RC_EXIT(rc, "ctx_init_internal failed");
        pthread_create(&thread, NULL,ctx_rrq_rx,p_ctx);
        //do clone
        rc = ioctl_dk_capi_clone(p_ctx, src_ctx_id,src_adap_fd);
        CHECK_RC_EXIT(rc, "clone ioctl failed");
        //do read data
        for (i=0; i< MAX_RES_HANDLE;i++)
        {
            if (RES_CLOSED == resource[i])
                continue;
            p_ctx->rsrc_handle = resource[i];
            p_ctx->res_hndl = p_ctx->rsrc_handle & RES_HNDLR_MASK;
            nlba = (i+1)*p_ctx->chunk_size;
            for (st_lba=0;st_lba<nlba; st_lba+=(NUM_CMDS*stride))
            {
                rc = send_read(p_ctx,st_lba,stride);
                CHECK_RC_EXIT(rc,"send_read failed\n");
                rc = rw_cmp_buf_cloned(p_ctx, st_lba);
                CHECK_RC_EXIT(rc,"rw_cmp_buf_cloned failed\n");
            }
        }
        sleep(1);
        //now create closed resources
        p_ctx->flags = DK_UVF_ALL_PATHS;
        for (i=0; i < 5;i++)
        {
            p_ctx->lun_size = (cl_index[i]+1)*p_ctx->chunk_size;
            rc = create_res(p_ctx);
            CHECK_RC_EXIT(rc,"res_create failed\n");
            resource[cl_index[i]] = p_ctx->rsrc_handle;
        }
        //do io on new resources
        p_ctx->st_lba = 0;
        for (i=0;i<5;i++)
        {
            p_ctx->last_lba = ((cl_index[i]+1)*p_ctx->chunk_size) -1;
            p_ctx->res_hndl = resource[cl_index[i]] & RES_HNDLR_MASK;
            rc = do_io(p_ctx, stride);
            CHECK_RC_EXIT(rc, "do_io failed\n");
        }
        pthread_cancel(thread);
        ctx_close(p_ctx);
        exit(0);
    } //child process end
    else
    {
        //create pthread
        sleep(1); //let child process do clone & read written data
        pthread_create(&thread, NULL, ctx_rrq_rx, p_ctx);
        //do open closed res
        //now create closed resources
        p_ctx->flags = DK_UVF_ALL_PATHS;
        for (i=0; i < 5;i++)
        {
            p_ctx->lun_size = (cl_index[i]+1)*p_ctx->chunk_size;
            rc = create_res(p_ctx);
            CHECK_RC_EXIT(rc,"res_create failed\n");
            resource[cl_index[i]] = p_ctx->rsrc_handle;
        }
        //do resize all resources & IO
        for (i=0;i<MAX_RES_HANDLE;i++)
        {
            p_ctx->req_size = (rand()%MAX_RES_HANDLE +1) * p_ctx->chunk_size;
            p_ctx->rsrc_handle = resource[i];
            p_ctx->res_hndl = p_ctx->rsrc_handle & RES_HNDLR_MASK;
            rc = ioctl_dk_capi_vlun_resize(p_ctx);
            CHECK_RC(rc, "dk_capi_resize_ioctl failed\n");
            rc = do_io(p_ctx, stride);
            CHECK_RC(rc, "do_io failed\n");
        }
        //close res
        for (i=0;i<MAX_RES_HANDLE;i++)
        {
            p_ctx->rsrc_handle = resource[i];
            rc = close_res(p_ctx);
            CHECK_RC(rc, "cose_res failed\n");
        }

        pthread_cancel(thread);
        ctx_close(p_ctx);
        rc = wait4all();
    }
    return rc;
}
// 7.1.218 : Pass context token to different process & do REUSE
int test_attach_reuse_diff_proc()
{
    int rc=0;
    int nDisk;
    struct flash_disk cfDisk[2];
    int cstat;
    struct ctx myctx;
    struct ctx *p_ctx = &myctx;

    pid = getpid();

    nDisk = get_flash_disks(cfDisk, FDISKS_SAME_ADPTR);
    if (nDisk < 2)
    {
        fprintf(stderr,"Failed to find 2 flash disks from same adapter..\n");
        return -1;
    }

    // sanity check for AIX!
    //#ifdef _AIX
    //  if ( cfDisk[0].devno != cfDisk[1].devno ) return 1;
    //#endif

    rc = ctx_init2(p_ctx, cfDisk[0].dev, DK_AF_ASSIGN_AFU, cfDisk[0].devno[0]);
    CHECK_RC(rc, "p_ctx Context init failed");

    rc = fork();
    if ( rc == -1 ) CHECK_RC(1, "fork() failed");

    // child process
    if ( rc == 0 )
    {
        pid = getpid();

#ifdef _AIX
        rc = ctx_init2(p_ctx, cfDisk[1].dev,
                       DK_AF_REUSE_CTX, cfDisk[0].devno[0]);
        if ( 0 == rc )
            CHECK_RC_EXIT(1, "Context init with DK_AF_REUSE_CTX did not fail");
#else
        rc = ctx_init2(p_ctx, cfDisk[1].dev,
                       DK_CXLFLASH_ATTACH_REUSE_CONTEXT, cfDisk[0].devno[0]);
        if ( 0 == rc )
            CHECK_RC_EXIT(1, "Context init with DK_CXLFLASH_ATTACH_REUSE_CONTEXT did not fail");
#endif

        exit(0);
    }
    else
    {
        // Probe child's exit status.
        if ( wait(&cstat) == -1 )
            CHECK_RC(1, "Failed while wait() for child");

        // We expect child to exit itself
        if (WIFEXITED(cstat))
        {
            // We expect child to exit with rc 0 only !
            if ( WEXITSTATUS(cstat) != 0 ) rc=1;
            else rc=0;
        }
    }

    cleanup(p_ctx, -1);

    return rc;
}
// 7.1.201 : Queue up commands, do not wait for completion and
// exit w/o detach/close,
// and do detach/close while commands in queue
int test_spio_exit()
{
    int rc;
    int isFailed=0;
    int i, nTimes;
    pid_t cpid;
    int cstat;
    struct ctx myctx;
    struct ctx *p_ctx = &myctx;
    pthread_t threadId, ioThreadId;
    do_io_thread_arg_t ioThreadData;
    do_io_thread_arg_t * p_ioThreadData=&ioThreadData;
    __u64 chunk = 0x10;
    __u64 nlba;
    __u64 stride= 0x10000;

    for (i=0, nTimes=50; i<nTimes; i++)
    {
        rc = fork();
        if ( rc == -1 ) CHECK_RC(1, "fork() failed");

        // child process
        if ( rc == 0 )
        {
            signal(SIGABRT, sig_handle);
            signal(SIGSEGV, sig_handle);
            // pid used to create unique data patterns & logging from util !
            pid = getpid();
            debug("...... Child process: Iteration : %d .....\n",i);
            //ctx_init with default flash disk & devno
            rc = ctx_init(p_ctx);
            CHECK_RC(rc, "Context init failed");

            //thread to handle AFU interrupt & events
            rc = pthread_create(&threadId, NULL, ctx_rrq_rx, p_ctx);
            CHECK_RC(rc, "pthread_create failed");

            // Test with vluns one after another
            if ( i < nTimes/5 )
            {
                nlba = chunk * p_ctx->chunk_size;
                //create vlun
                rc = create_resource(p_ctx,nlba, DK_UVF_ALL_PATHS, LUN_VIRTUAL);
                CHECK_RC(rc, "create LUN_VIRTUAL failed");
            }
            // Test with pluns one after another
            else if ( i > nTimes/5 && i < 2*nTimes/5 )
            {
                // Create PLUN
                rc = create_resource(p_ctx, 0, DK_UDF_ASSIGN_PATH, LUN_DIRECT);
                CHECK_RC(rc, "create LUN_DIRECT failed");
                stride = 0x10000;
            }
            // Test with vluns/pluns alternately !
            else if ( i % 2 )
            {
                nlba = chunk * p_ctx->chunk_size;
                //create vlun
                rc = create_resource(p_ctx,nlba, DK_UVF_ALL_PATHS, LUN_VIRTUAL);
                CHECK_RC(rc, "create LUN_VIRTUAL failed");
            }
            else
            {
                // Create PLUN
                rc = create_resource(p_ctx, 0, DK_UDF_ASSIGN_PATH, LUN_DIRECT);
                CHECK_RC(rc, "create LUN_DIRECT failed");
                stride = 0x10000;
            }

            // Make sure at-least 1 IO is successful before proceeding !
            rc = do_io(p_ctx, stride);
            CHECK_RC_EXIT(rc, "Initial IO attempt failed");

            // We wish to do IO in a different thread... Setting up for that !
            p_ioThreadData->p_ctx=p_ctx;
            p_ioThreadData->stride=stride;
            p_ioThreadData->loopCount=100;
            rc = pthread_create(&ioThreadId,NULL,
                                do_io_thread, (void *)p_ioThreadData);
            CHECK_RC_EXIT(rc, "do_io_thread() pthread_create failed");

            // Sleep for a sec before exiting
            sleep(1);

            if ( i % 2 )
            {
                debug("%d:Exiting w/o detach/close",pid);
            }
            else
            {
                debug("%d:Exiting after detach/close",pid);
                cleanup(p_ctx, threadId);
            }

            exit(10);
        }
        // parent process
        else
        {
            pid = getpid();

            cpid = rc;

            // Probe child's exit status.
            if ( wait(&cstat) == -1 )
                CHECK_RC(1, "Failed while wait() for child");

            // We expect child to exit itself
            if (WIFEXITED(cstat))
            {
                debug("Exiting w/o getting killed %d \n",cpid);
                // We expect child to exit with rc 10 only !
                if ( WEXITSTATUS(cstat) != 10 ) isFailed=1;
            }
            else if (WIFSIGNALED(cstat))
            {
                //isFailed=1;
                debug("%d :  killed by %d signal\n", cpid, WTERMSIG(cstat));
                if (WCOREDUMP(cstat)) //expected if exiting without cancelling poll thread
                    fprintf(stderr, "%d :  was core dupmed ...\n", cpid);
            }

            debug("pid %d exited with rc = %d\n", cpid, cstat);
        }
    }

    return isFailed;
}
// 7.1.200 : Send signal to kill process when it has cmds queued.
int test_spio_killprocess()
{
    int rc;
    int isFailed=0;
    int i, nTimes;
    pid_t cpid;
    int cstat;
    struct ctx myctx;
    struct ctx *p_ctx = &myctx;
    struct sigaction action;
    sigset_t sigset;
    pthread_t threadId;
    __u64 chunk = 0x10;
    __u64 nlba;
    __u64 stride=0x1000;

    pid = getpid();

    sigemptyset(&sigset);
    sigprocmask(SIG_SETMASK, &sigset, NULL);

    // Set up the signal handler
    action.sa_handler = callme;
    action.sa_flags = 0;
    sigemptyset(&action.sa_mask);

    if (sigaction(SIGUSR1, &action, NULL) < 0)
        CHECK_RC(1, "sigaction() failed");

    char *str = getenv("LONG_RUN");
    if (str == NULL) nTimes=10;
    else nTimes=100;

    for (i=0; i<nTimes; i++)
    {
        rc = fork();
        if ( rc == -1 ) CHECK_RC(1, "fork() failed");

        // child process
        if ( rc == 0 )
        {
            debug("...... Child process: Iteration : %d .....\n",i);
            // pid used to create unique data patterns & logging from util !
            pid = getpid();

            //ctx_init with default flash disk & devno
            rc = ctx_init(p_ctx);
            CHECK_RC(rc, "Context init failed");

            //thread to handle AFU interrupt & events
            rc = pthread_create(&threadId, NULL, ctx_rrq_rx, p_ctx);
            CHECK_RC(rc, "pthread_create failed");

            // Test with vluns one after another
            if ( i < nTimes/5 )
            {
                nlba = chunk * p_ctx->chunk_size;
                //create vlun
                rc = create_resource(p_ctx,nlba, DK_UVF_ALL_PATHS, LUN_VIRTUAL);
                CHECK_RC(rc, "create LUN_VIRTUAL failed");
            }
            // Test with pluns one after another
            else if ( i > nTimes/5 && i < 2*nTimes/5 )
            {
                // Create PLUN
                rc = create_resource(p_ctx, 0, DK_UDF_ASSIGN_PATH, LUN_DIRECT);
                CHECK_RC(rc, "create LUN_DIRECT failed");
                stride=0x10000;
            }
            // Test with vluns/pluns alternately !
            else if ( i % 2 )
            {
                nlba = chunk * p_ctx->chunk_size;
                //create vlun
                rc = create_resource(p_ctx,nlba, DK_UVF_ALL_PATHS, LUN_VIRTUAL);
                CHECK_RC(rc, "create LUN_VIRTUAL failed");
                stride=0x1000;
            }
            else
            {
                // Create PLUN
                rc = create_resource(p_ctx, 0, DK_UDF_ASSIGN_PATH, LUN_DIRECT);
                CHECK_RC(rc, "create LUN_DIRECT failed");
                stride=0x10000;
            }

            rc = do_io(p_ctx, stride);

            // Signal parent to kill itself after this point.
            kill(getppid(), SIGUSR1);

            // Exit at this point if we failed in initial IO
            CHECK_RC_EXIT(rc, "Initial IO failed");

            // Keep driving IO till killed
            for (;;) do_io(p_ctx, stride);
        }
        // parent process
        else
        {
            pid = getpid();

            cpid = rc;
            // Wait for child to complete at-least 1 successful IO.
            pause();

            // Let the child IO go on some more time !
            sleep(1);

            // Send signal 9 - process can't ignore it;
            kill(cpid, 9);

            // Probe child's exit status.
            if ( wait(&cstat) == -1 )
                CHECK_RC(1, "Failed while wait() for child");

            // We don't expect child to exit itself
            if (WIFEXITED(cstat)) isFailed = 1;
            else if (WIFSIGNALED(cstat))
            {
                // We expect this !
                debug("%d :  killed by %d signal\n", cpid, WTERMSIG(cstat));
                if (WCOREDUMP(cstat))
                    fprintf(stderr, "%d :  was core dupmed ...\n", cpid);
            }

            debug("pid %d exited with rc = %d\n", cpid, cstat);
        }
    }

    return isFailed;
}
Exemple #6
0
int ioctl_7_1_196()
{
    int rc,i,j;
    struct ctx myctx[21],myctx_1, myctx_2;
    struct ctx *p_ctx[21],*p_ctx_1,*p_ctx_2;
    __u64 stride=0x1000,st_lba=0;
    pthread_t thread[20];
    struct flash_disk disks[MAX_FDISK];
    char disk1[30];
    char disk2[30];

    int cfdisk = MAX_FDISK;

    pid = getpid();

    cfdisk = get_flash_disks(disks, FDISKS_SAME_ADPTR);
    //need to check the number of disks
    if (cfdisk < 2)
    {
        fprintf(stderr,"Must have 2 flash disks..\n");
        TESTCASE_SKIP("Need disk from same adapter and each disk multipathed");
        return 0;
    }

    strcpy(disk1,disks[0].dev);
    strcpy(disk2,disks[1].dev);

    // creating first context

    for (i=0;i<21;i++)
    {
        p_ctx[i]=&myctx[i];
    }
    p_ctx_1=&myctx_1;
    p_ctx_2=&myctx_2;
    debug("1ST PROCEDURE\n");
    // using p_ctx[[0] for LUN direct for firect disk
    /*    rc = ctx_init2(p_ctx[0], disks[0].dev, DK_AF_ASSIGN_AFU, disks[0].devno[0]);
        pthread_create(&thread[0], NULL, ctx_rrq_rx, p_ctx[0]);
     */
    /*    rc = create_resource(p_ctx[0], 0, DK_UDF_ASSIGN_PATH, LUN_DIRECT);
        CHECK_RC(rc, "create LUN_DIRECT failed");
     */
    // creating another 19 context LUN VIRTUAL
    for ( i=2;i<21;i++)
    {
        sleep(2);
        rc = ctx_init2(p_ctx[i], disks[1].dev, DK_AF_ASSIGN_AFU, disks[1].devno[0]);
        rc=create_resource(p_ctx[i], p_ctx[i]->chunk_size, DK_UVF_ASSIGN_PATH, LUN_VIRTUAL);
    }


    // do context reuse for direct LUN
    strcpy(p_ctx[0]->dev,disks[0].dev);
    strcpy(p_ctx[1]->dev,disks[1].dev);
    p_ctx[0]->fd = open_dev(disks[0].dev, O_RDWR);
    if (p_ctx[0]->fd < 0)
    {
        fprintf(stderr, "open() failed: device %s, errno %d\n", disks[0].dev, errno);
        g_error = -1;
        return -1;
    }
    p_ctx[1]->fd = open_dev(disks[1].dev, O_RDWR);  //Hoping to open second disk
    if (p_ctx[1]->fd < 0)
    {
        fprintf(stderr, "open() failed: device %s, errno %d\n", disks[1].dev, errno);
        g_error = -1;
    }
#ifdef _AIX
    rc = ioctl_dk_capi_query_path(p_ctx[0]);
    CHECK_RC(rc, "DK_CAPI_QUERY_PATH failed");
#else
    //TBD for linux
#endif
    p_ctx[0]->work.num_interrupts = p_ctx[1]->work.num_interrupts = 4;


    rc=ioctl_dk_capi_attach_reuse(p_ctx[0],p_ctx[1],LUN_DIRECT);

    //         CHECK_RC(rc, "DK_CAPI_ATTACH with reuse flag failed");


    if ( rc != 0 )
    {
        fprintf(stderr,"LUN DIRECT got attached to new disk with VLUN, should have succeeded");
        return rc;
    }


    // initiate I/O on all the LUNs
    for (i=2;i<21;i++)
    {
        pthread_create(&thread[i], NULL, ctx_rrq_rx, p_ctx[i]);
        rc = do_io(p_ctx[i], stride);
    }
    if ( rc != 0 )
    {       fprintf(stderr,"io on some LUN failed");
        return rc;
    }

    /* using a goto-label removes the compile warning (-O3 issue) */
    i=2;
    for_loop:
        pthread_cancel(thread[i]);
        close_res(p_ctx[i]);
        if (++i < 21) {goto for_loop;}

    ctx_close(p_ctx[2]);
    debug("2nd PROCEDURE\n");
   
    // procedure 2 of the same case
    debug("%d: ........Phase 1 done.. Starting 2nd Phase........\n",getpid());
    memset(p_ctx_1, 0, sizeof(struct ctx));

    memset(p_ctx_2, 0, sizeof(struct ctx));
    // open the first flash disk in write mode and create a DIRECT LUN

    // restoring from backup
    strcpy(disks[0].dev,disk1);
    p_ctx_1->fd = open_dev(disks[0].dev, O_WRONLY);
    if (p_ctx_1->fd < 0)
    {
        fprintf(stderr, "open() failed: device %s, errno %d\n", disks[0].dev, errno);
        return -1;
    }
    rc = ctx_init2(p_ctx_1, disks[0].dev, DK_AF_ASSIGN_AFU, disks[0].devno[0]);
    pthread_create(&thread[0], NULL, ctx_rrq_rx, p_ctx_1);
    CHECK_RC(rc, "create context failed");

    rc = create_resource(p_ctx_1, 0, DK_UDF_ASSIGN_PATH, LUN_DIRECT);
    CHECK_RC(rc, "create LUN_DIRECT failed");

    // open the same flash disk in read mode again.
    p_ctx_2->fd = open_dev(disks[0].dev, O_RDONLY);
    if (p_ctx_2->fd < 0)
    {
        fprintf(stderr, "open() failed: device %s, errno %d\n", disks[0].dev, errno);
        return -1;
    }
    rc = ctx_init2(p_ctx_2, disks[0].dev, DK_AF_ASSIGN_AFU, disks[0].devno[0]);
    pthread_create(&thread[1], NULL, ctx_rrq_rx, p_ctx_2);
    CHECK_RC(rc, "create context failed");
    rc = create_resource(p_ctx_2, 0, DK_UDF_ASSIGN_PATH, LUN_DIRECT);
    CHECK_RC(rc, "create LUN_DIRECT failed");

    // now write to the disk and then read
    for (st_lba = 0; st_lba <= p_ctx_1->last_lba; st_lba += (NUM_CMDS*stride))
    {
        rc = send_write(p_ctx_1, st_lba, stride, pid);
        CHECK_RC(rc, "send_write failed");
        rc = send_read(p_ctx_2, st_lba, stride);
        CHECK_RC(rc, "send_read failed");
        /*if (rc !=0 )
        {
            rc = rw_cmp_buf(p_ctx_1, st_lba);
            if (rc != 0)
            {
                fprintf(stderr,"buf cmp failed for lba 0x%lX,rc =%d\n",st_lba,rc);
                break;
            }
        }*/
    }
    if ( rc != 0 )
        return rc;

    for (i=0;i<2;i++)
    {
        pthread_cancel(thread[i]);
    }

    //close_res(p_ctx_1);
    ctx_close(p_ctx_1);
    //close_res(p_ctx_2);
    ctx_close(p_ctx_2);

    debug("3rd PROCEDURE\n");
    debug("%d: ........Phase 2 done.. Starting 3rd Phase........\n",getpid());
    // case 3 of the same case
    // creating multiple process for LUN_DIRECT creation.
    for (j=0;j<long_run;j++)
    {
        for (i=0; i<20;i++)
        {
            if ( 0 == fork())
            { rc = ctx_init(p_ctx[i]);
                CHECK_RC_EXIT(rc, "Context init failed");
                // CHECK_RC(rc, "Context init failed");
                //thread to handle AFU interrupt & events

                rc = create_resource(p_ctx[i], 0, DK_UDF_ASSIGN_PATH , LUN_DIRECT);
                CHECK_RC_EXIT(rc, "create LUN_DIRECT failed");
                // do io on context
                pthread_create(&thread[i], NULL, ctx_rrq_rx, p_ctx[i]);
                stride=0x1000;
                sleep(2);
                //do_io(p_ctx[i], stride);
                pthread_cancel(thread[i]);
                close_res(p_ctx[i]);
                exit(rc);
            }
        }
        wait4all();
    }

    return 0;

}