/* DF-3053 - nfsm_mbuftouio ignores copyout fault.
 * usage: df3053 <file-on-nfs>
 * thread A: read(fd, mapped, 4096); thread B: after 300ms mprotect(PROT_NONE).
 * BUG: read returns 4096 (success) while the mapping still holds 0x5A.
 * CORRECT: read returns -1/EFAULT.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
static char *region; static volatile int started=0;
static void *unmapper(void *a){
    long ms=0; while(!started && ms<5000){usleep(1000);ms++;}
    usleep(300000);                       /* read() is now blocked on the RPC */
    mprotect(region, 8192, PROT_NONE);
    printf("B: mprotect(PROT_NONE) done at t=300ms\n");
    return NULL;
}
int main(int argc,char**argv){
    pthread_t t; int fd; ssize_t r; pthread_mutex_t m=PTHREAD_MUTEX_INITIALIZER;(void)m;
    if(argc<2){fprintf(stderr,"usage: df3053 file\n");return 2;}
    fd=open(argv[1],O_RDONLY); if(fd<0){perror("open");return 1;}
    region=mmap(NULL,8192,PROT_READ|PROT_WRITE,MAP_ANON|MAP_PRIVATE,-1,0);
    if(region==MAP_FAILED){perror("mmap");return 1;}
    memset(region,0x5A,8192);
    pthread_create(&t,NULL,unmapper,NULL);
    started=1;
    errno=0; r=read(fd,region,4096);
    int e=errno;
    pthread_join(t,NULL);
    /* re-allow reading to inspect contents */
    mprotect(region,8192,PROT_READ);
    int stale=1; for(int i=0;i<4096;i++) if(((unsigned char*)region)[i]!=0x5A){stale=0;break;}
    printf("A: read() ret=%zd errno=%d (%s)\n",r,e,e?strerror(e):"-");
    printf("RESULT: %s (buffer %s 0x5A-stale)\n",
        (r==4096&&stale)?"BUG_REPRODUCED_full_success_stale_data":
        (r==4096&&!stale)?"PARTIAL_data_delivered":
        "CORRECT_fault_reported",
        stale?"still":"modified");
    return 0;
}
