Hello,
I am developing an application using XFS/DMAPI on Linux 2.4.
My application registers for DM_EVENT_READ and DM_EVENT_WRITE events
on a file, then calls dm_punch_hole() on that file. The event handlers
use dm_write_invis() to re-populate the file data on demand (including
re-populating all of the original file data before allowing the
first write operation to continue).
This works fine for READ events. However, whenever I get a WRITE
event, the call to dm_write_invis() blocks my program. If I kill
(ctrl-C) the application that triggered the WRITE event, then the
dm_write_invis() call returns successfully and my program continues.
I have attached a test program that illustrates this behaviour.
The XFS filesystem is mounted on /mnt and I use a file "/mnt/TESTFILE".
Reading from the file works:
---
mmontour:/home/mmontour# dd if=/mnt/TESTFILE bs=100 count=1
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB1+0records
in
1+0 records out
---
and my DMAPI program produces the following output:
---
mmontour:/home/mmontour# ./a.out
SGI DMAPI (XDSM) API, Release 1.0.
Waiting for event...
Got DM_EVENT_READ, de_offset 0, de_length 100
Requesting DM_RIGHT_EXCL
Calling dm_write_invis()
dm_write_invis() returns 100
Sending DM_RESP_CONTINUE
Done
---
However, when I try to write:
---
mmontour:/home/mmontour# dd if=/dev/zero of=/mnt/TESTFILE bs=100 count=1
---
my DMAPI program hangs after:
---
mmontour:/home/mmontour# ./a.out
SGI DMAPI (XDSM) API, Release 1.0.
Waiting for event...
Got DM_EVENT_WRITE, de_offset 0, de_length 100
Requesting DM_RIGHT_EXCL
Calling dm_write_invis()
---
--------------------------------
Kernel is 2.4.24-pre1 plus the xfs-2.4.24-pre1-all-i386.bz2 patch.
From dmesg:
SGI XFS snapshot 2.4.24-pre1-2003-12-11_23:47_UTC with ACLs, no debug
enabled
XFS config options are:
CONFIG_XFS_FS=y
# CONFIG_XFS_QUOTA is not set
CONFIG_XFS_POSIX_ACL=y
# CONFIG_XFS_RT is not set
CONFIG_XFS_DMAPI=y
# CONFIG_XFS_TRACE is not set
# CONFIG_XFS_DEBUG is not set
Additional information is available on request. Am I doing something
wrong in my program, is this a known limitation of Linux/XFS/DMAPI,
or is this a bug?
-Mike Montour <mmontour@xxxxxxxxxx>
--------------------------------
#include <stdio.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <xfs/dmapi.h>
#define MTPT "/mnt"
#define TESTFILE "/mnt/TESTFILE"
int main(int argc, char *argv[])
{
char *str = NULL;
int rc = 0;
int myfile;
char *data = NULL;
int nbytes;
char buf[256];
size_t bufBytes;
dm_sessid_t Session;
dm_eventset_t eSet;
void *fsHandle;
size_t fsHandle_len;
void *fileHandle;
size_t fileHandle_len;
void *eventHandle;
size_t eventHandle_len;
dm_boolean_t exactflag;
dm_region_t rFlags;
dm_eventmsg_t *eventMsg;
dm_data_event_t *dataEvent;
/* Setup */
rc = dm_init_service(&str);
assert(rc == 0);
printf("%s\n", str);
rc = dm_create_session(DM_NO_SESSION, "test", &Session);
assert(rc == 0);
rc = dm_path_to_fshandle(MTPT, &fsHandle, &fsHandle_len);
assert(rc == 0);
DMEV_ZERO(eSet);
DMEV_SET(DM_EVENT_READ, eSet);
DMEV_SET(DM_EVENT_WRITE, eSet);
rc = dm_set_disp(Session, fsHandle, fsHandle_len, DM_NO_TOKEN, &eSet,
DM_EVENT_MAX);
assert(rc == 0);
/* Create file (removing old one if present) */
rc = unlink(TESTFILE);
assert((rc == 0) || (errno == ENOENT));
myfile = open(TESTFILE, O_WRONLY | O_CREAT, 0644);
data = (char *)malloc(100);
memset(data,'A',100);
nbytes = write(myfile, data, 100);
assert (nbytes == 100);
close(myfile);
free(data);
/* Register for notification and punch hole */
rc = dm_path_to_handle(TESTFILE, &fileHandle, &fileHandle_len);
assert(rc == 0);
rFlags.rg_offset = 0;
rFlags.rg_size = 0;
rFlags.rg_flags = DM_REGION_READ | DM_REGION_WRITE;
rc = dm_set_region(Session, fileHandle, fileHandle_len, DM_NO_TOKEN, 1,
&rFlags, &exactflag);
assert(rc == 0);
rc = dm_punch_hole(Session, fileHandle, fileHandle_len, DM_NO_TOKEN, 0,
0);
assert(rc == 0);
/* Get event */
printf("Waiting for event...\n");
fflush(stdout);
rc = dm_get_events(Session,1,DM_EV_WAIT,256,buf,&bufBytes);
assert(rc == 0);
eventMsg = (dm_eventmsg_t *)buf;
switch(eventMsg->ev_type)
{
case DM_EVENT_READ:
printf("Got DM_EVENT_READ, ");
break;
case DM_EVENT_WRITE:
printf("Got DM_EVENT_WRITE, ");
break;
default:
assert(0);
}
dataEvent = DM_GET_VALUE(eventMsg, ev_data, dm_data_event_t *);
printf("de_offset %lld, de_length %lld\n", dataEvent->de_offset,
dataEvent->de_length);
fflush(stdout);
eventHandle = DM_GET_VALUE(dataEvent, de_handle, void *);
eventHandle_len = DM_GET_LEN(dataEvent, de_handle);
/* Put data into file */
printf("Requesting DM_RIGHT_EXCL\n");
fflush(stdout);
rc = dm_request_right(Session, eventHandle, eventHandle_len,
eventMsg->ev_token, DM_RR_WAIT, DM_RIGHT_EXCL);
assert(rc == 0);
data = (char *)malloc(100);
memset(data,'B',100);
printf("Calling dm_write_invis()\n");
fflush(stdout);
rc = dm_write_invis(Session, eventHandle, eventHandle_len,
eventMsg->ev_token, 0, 0, 100, data);
printf("dm_write_invis() returns %d\n", rc);
fflush(stdout);
rc = dm_release_right(Session, eventHandle, eventHandle_len,
eventMsg->ev_token);
assert(rc == 0);
/* Respond to event*/
printf("Sending DM_RESP_CONTINUE\n");
fflush(stdout);
rc = dm_respond_event(Session, eventMsg->ev_token, DM_RESP_CONTINUE, 0,
0, NULL);
assert(rc == 0);
/* Shutdown */
dm_destroy_session(Session);
printf("Done\n");
fflush(stdout);
return 0;
}
|