Viewing file: dmapi_event.c (24.84 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */
#include "dmapi_private.h" #include <linux/module.h> /* for EXPORT_SYMBOL */
/* The "rights" portion of the DMAPI spec is not currently implemented. A framework for rights is provided in the code, but turns out to be a noop in practice. The following comments are a brain dump to serve as input to the poor soul that eventually has to get DMAPI rights working in IRIX.
A DMAPI right is similar but not identical to the mrlock_t mechanism already used within the kernel. The similarities are that it is a sleeping lock, and that a multiple-reader, single-writer protocol is used. How locks are obtained and dropped are different however. With a mrlock_t, a thread grabs the lock, does some stuff, then drops the lock, and all other threads block in the meantime (assuming a write lock). There is a one-to- one relationship between the lock and the thread which obtained the lock. Not so with DMAPI right locks. A DMAPI lock is associated with a particular session/token/hanp/hlen quad; since there is a dm_tokdata_t structure for each such quad, you can think of it as a one-to-one relationship between the lock and a dm_tokdata_t. Any application thread which presents the correct quad is entitled to grab or release the lock, or to use the rights associated with that lock. The thread that grabs the lock does not have to be the one to use the lock, nor does it have to be the thread which drops the lock. The lock can be held for very long periods of time, even across multiple systems calls by multiple application threads. The idea is that a coordinated group of DMAPI application threads can grab the lock, issue a series of inode accesses and/or updates, then drop the lock, and be assured that no other thread in the system could be modifying the inode at the same time. The kernel is expected to blindly trust that the application will not forget to unlock inodes it has locked, and will not deadlock itself against the kernel.
There are two types of DMAPI rights, file object (inode) and filesystem object (superblock?). An inode right is the equivalent of the combination of both the XFS ilock and iolock; if held exclusively, no data or metadata within the file can be changed by non-lock-holding threads. The filesystem object lock is a little fuzzier; I think that if it is held, things like unmounts can be blocked, plus there is an event mask associated with the filesystem which can't be updated without the lock. (By the way, that event mask is supposed to be persistent in the superblock; add that to your worklist :-)
All events generated by XFS currently arrive with no rights, i.e. DM_RIGHT_NULL, and return to the filesystem with no rights. It would be smart to leave it this way if possible, because it otherwise becomes more likely that an application thread will deadlock against the kernel if the one responsible for calling dm_get_events() happens to touch a file which was locked at the time the event was queued. Since the thread is blocked, it can't read the event in order to find and drop the lock. Catch-22. If you do have events that arrive with non-null rights, then dm_enqueue() needs to have code added for synchronous events which atomically switches the right from being a thread-based right to a dm_tokdata_t-based right without allowing the lock to drop in between. You will probably have to add a new dm_fsys_vector entry point to do this. The lock can't be lost during the switch, or other threads might change the inode or superblock in between. Likewise, if you need to return to the filesystem holding a right, then you need a DMAPI-to-thread atomic switch to occur, most likely in dm_change_right(). Again, the lock must not be lost during the switch; the DMAPI spec spends a couple of pages stressing this. Another dm_fsys_vector entry point is probably the answer.
There are several assumptions implied in the current layout of the code. First of all, if an event returns to the filesystem with a return value of zero, then the filesystem can assume that any locks (rights) held at the start of the event are still in effect at the end of the event. (Note that the application could have temporarily dropped and reaquired the right while the event was outstanding, however). If the event returns to the filesystem with an errno, then the filesystem must assume that it has lost any and all rights associated with any of the objects in the event. This was done for a couple of reasons. First of all, since an errno is being returned, most likely the filesystem is going to immediately drop all the locks anyway. If the DMAPI code was required to unconditionally reobtain all locks before returning to the filesystem, then dm_pending() wouldn't work for NFS server threads because the process would block indefinitely trying to get its thread-based rights back, because the DMAPI-rights associated with the dm_tokdata_t in the outstanding event would prevent the rights from being obtained. That would be a bad thing. We wouldn't be able to let users Cntl-C out of read/write/truncate events either.
If a case should ever surface where the thread has lost its rights even though it has a zero return status, or where the thread has rights even though it is returning with an errno, then this logic will have to be reworked. This could be done by changing the 'right' parameters on all the event calls to (dm_right_t *), so that they could serve both as IN and OUT parameters.
Some events such as DM_EVENT_DESTROY arrive without holding a vnode reference; if you don't have a vnode reference, you can't have a right on the file.
One more quirk. The DM_EVENT_UNMOUNT event is defined to be synchronous when it's behavior is asynchronous. If an unmount event arrives with rights, the event should return with the same rights and should NOT leave any rights in the dm_tokdata_t where the application could use them. */
#define GETNEXTOFF(vdat) ((vdat).vd_offset + (vdat).vd_length) #define HANDLE_SIZE(tdp) \ ((tdp)->td_type & DM_TDT_VFS ? FSHSIZE : XFS_HSIZE((tdp)->td_handle))
/* Given a behavior descriptor pointer in a filesystem known to support DMAPI, build a tdp structure for the corresponding vnode. */
static dm_tokdata_t * dm_bhv_data( bhv_desc_t *bdp, dm_right_t right, int referenced) /* != 0, caller holds vnode reference */ { int error; dm_tokdata_t *tdp; vnode_t *vp = BHV_TO_VNODE(bdp);
tdp = kmem_alloc(sizeof(*tdp), KM_SLEEP);
tdp->td_next = NULL; tdp->td_tevp = NULL; tdp->td_app_ref = 0; tdp->td_orig_right = right; tdp->td_right = right; tdp->td_flags = DM_TDF_ORIG; if (referenced) { tdp->td_flags |= DM_TDF_EVTREF; }
if (vp->v_type == VREG) { tdp->td_type = DM_TDT_REG; } else if (vp->v_type == VDIR) { tdp->td_type = DM_TDT_DIR; } else if (vp->v_type == VLNK) { tdp->td_type = DM_TDT_LNK; } else { tdp->td_type = DM_TDT_OTH; }
if (referenced) { tdp->td_bdp = bdp; } else { tdp->td_bdp = 0; } tdp->td_vcount = 0;
if ((error = dm_vp_to_handle(vp, &tdp->td_handle)) != 0) { panic("dm_bhv_data: dm_vp_to_handle failed for vp %p in " "a DMAPI filesystem, errno %d\n", vp, error); }
return(tdp); }
/* Given a vfs pointer to a filesystem known to support DMAPI, build a tdp structure for that vfsp. */ static dm_tokdata_t * dm_vfs_data( vfs_t *vfsp, vnode_t *vp, /* will be NULL for DM_EVENT_UNMOUNT */ dm_right_t right) { dm_tokdata_t *tdp;
tdp = kmem_alloc(sizeof(*tdp), KM_SLEEP);
tdp->td_next = NULL; tdp->td_tevp = NULL; tdp->td_app_ref = 0; tdp->td_orig_right = right; tdp->td_right = right; tdp->td_flags = DM_TDF_ORIG; if (vp) { tdp->td_flags |= DM_TDF_EVTREF; } tdp->td_type = DM_TDT_VFS; if (vp) { tdp->td_bdp = bhv_base_unlocked(VN_BHV_HEAD(vp)); } else { tdp->td_bdp = 0; } tdp->td_vcount = 0;
bcopy(vfsp->vfs_altfsid, &tdp->td_handle.ha_fsid, sizeof(fsid_t)); bzero((char *)&tdp->td_handle.ha_fsid + sizeof(fsid_t), sizeof(tdp->td_handle) - sizeof(fsid_t));
return(tdp); }
/* Link a tdp structure into the tevp. */
static void dm_add_handle_to_event( dm_tokevent_t *tevp, dm_tokdata_t *tdp) { tdp->td_next = tevp->te_tdp; tevp->te_tdp = tdp; tdp->td_tevp = tevp; }
/* Generate the given data event for the vnode, and wait for a reply. The caller must guarantee that the vnode's reference count is greater than zero so that the filesystem can't disappear while the request is outstanding. */
int dm_send_data_event( dm_eventtype_t event, bhv_desc_t *bdp, dm_right_t vp_right, /* current right for vp */ off_t offset, size_t length, int flags) /* 0 or DM_FLAGS_NDELAY */ { dm_data_event_t *datap; dm_tokevent_t *tevp; dm_tokdata_t *tdp; vnode_t *vp; int error;
vp = BHV_TO_VNODE(bdp); tdp = dm_bhv_data(bdp, vp_right, /* reference held */ 1);
/* Calculate the size of the event in bytes, create an event structure for it, and insert the file's handle into the event. */
tevp = dm_evt_create_tevp(event, HANDLE_SIZE(tdp), (void **)&datap); dm_add_handle_to_event(tevp, tdp);
/* Now fill in all the dm_data_event_t fields. */
datap->de_handle.vd_offset = sizeof(*datap); datap->de_handle.vd_length = HANDLE_SIZE(tdp); bcopy(&tdp->td_handle, (char *)datap + datap->de_handle.vd_offset, datap->de_handle.vd_length); datap->de_offset = offset; datap->de_length = length;
/* Queue the message and wait for the reply. */
error = dm_enqueue_normal_event(vp->v_vfsp, tevp, flags);
/* If no errors occurred, we must leave with the same rights we had upon entry. If errors occurred, we must leave with no rights. */
dm_evt_rele_tevp(tevp, error);
return(error); }
/* Generate the destroy event for the vnode and wait until the request has been queued. The caller does not hold a vnode reference or a right on the vnode, but it must otherwise lock down the vnode such that the filesystem can't disappear while the request is waiting to be queued. While waiting to be queued, the vnode must not be referenceable either by path or by a call to dm_handle_to_vp(). */
int dm_send_destroy_event( bhv_desc_t *bdp, dm_right_t vp_right) /* always DM_RIGHT_NULL */ { dm_fsys_vector_t *fsys_vector; dm_tokevent_t *tevp; dm_tokdata_t *tdp; dm_destroy_event_t *destp; dm_attrname_t attrname; vnode_t *vp; char *value; int value_len; int error;
vp = BHV_TO_VNODE(bdp); tdp = dm_bhv_data(bdp, vp_right, /* no reference held */ 0);
if ((error = dm_waitfor_destroy_attrname(vp->v_vfsp, &attrname)) != 0) return(error);
/* If a return-on-destroy attribute name exists for this filesystem, see if the object being deleted has this attribute. If the object doesn't have the attribute or if we encounter an error, then send the event without the attribute. */
value_len = -1; /* because zero is a valid attribute length */ if (attrname.an_chars[0] != '\0') { fsys_vector = dm_fsys_vector(bdp); (void)fsys_vector->get_destroy_dmattr(bdp, vp_right, &attrname, &value, &value_len); }
/* Now that we know the size of the attribute value, if any, calculate the size of the event in bytes, create an event structure for it, and insert the handle into the event. */
tevp = dm_evt_create_tevp(DM_EVENT_DESTROY, HANDLE_SIZE(tdp) + (value_len >= 0 ? value_len : 0), (void **)&destp); dm_add_handle_to_event(tevp, tdp);
/* Now fill in all the dm_destroy_event_t fields. */
destp->ds_handle.vd_offset = sizeof(*destp); destp->ds_handle.vd_length = HANDLE_SIZE(tdp); bcopy(&tdp->td_handle, (char *)destp + destp->ds_handle.vd_offset, destp->ds_handle.vd_length); if (value_len >= 0) { destp->ds_attrname = attrname; destp->ds_attrcopy.vd_length = value_len; if (value_len == 0) { destp->ds_attrcopy.vd_offset = 0; } else { destp->ds_attrcopy.vd_offset = GETNEXTOFF(destp->ds_handle); bcopy(value, (char *)destp + destp->ds_attrcopy.vd_offset, value_len); kmem_free(value, value_len); } }
/* Queue the message asynchronously. */
error = dm_enqueue_normal_event(vp->v_vfsp, tevp, 0);
/* Since we had no rights upon entry, we have none to reobtain before leaving. */
dm_evt_rele_tevp(tevp, 1);
return(error); }
/* The dm_mount_event_t event is sent in turn to all sessions that have asked for it until one either rejects it or accepts it. The filesystem is not going anywhere because the mount is blocked until the event is answered. */
int dm_send_mount_event( vfs_t *vfsp, /* filesystem being mounted */ dm_right_t vfsp_right, bhv_desc_t *bdp, /* mounted on directory */ dm_right_t vp_right, bhv_desc_t *rootbdp, dm_right_t rootvp_right, char *name1, /* mount path */ char *name2) /* filesystem device name */ { int error; dm_tokevent_t *tevp; dm_tokdata_t *tdp1; /* filesystem handle for event */ dm_tokdata_t *tdp2 = NULL; /* file handle for mounted-on dir. */ dm_tokdata_t *tdp3; /* file handle for root vnode */ dm_mount_event_t *mp; size_t nextoff; vnode_t *vp = NULL; /* mounted on directory */ vnode_t *rootvp = BHV_TO_VNODE(rootbdp);
/* Convert the vfsp to a filesystem handle, and vp and rootvp into file handles. vp (the mounted-on directory) may not have a handle if it is a different filesystem type such as EFS which does not support DMAPI. */
if(bdp) vp = BHV_TO_VNODE(bdp);
tdp1 = dm_vfs_data(vfsp, rootvp, vfsp_right);
if ((vp == NULL) || dm_check_dmapi_vp(vp)) { vp = NULL; /* assume we are mounting on non XFS */ } else { tdp2 = dm_bhv_data(bdp, vp_right, /* reference held */ 1); } tdp3 = dm_bhv_data(rootbdp, rootvp_right, /* reference held */ 1);
/* Calculate the size of the event in bytes, create an event structure for it, and insert the handles into the event. */
tevp = dm_evt_create_tevp(DM_EVENT_MOUNT, HANDLE_SIZE(tdp1) + (vp ? HANDLE_SIZE(tdp2) : 0) + HANDLE_SIZE(tdp3) + strlen(name1) + 1 + strlen(name2) + 1, (void **)&mp);
dm_add_handle_to_event(tevp, tdp1); if (vp) dm_add_handle_to_event(tevp, tdp2); dm_add_handle_to_event(tevp, tdp3);
/* Now fill in all the dm_mount_event_t fields. */
mp->me_handle1.vd_offset = sizeof(*mp); mp->me_handle1.vd_length = HANDLE_SIZE(tdp1); bcopy(&tdp1->td_handle, (char *) mp + mp->me_handle1.vd_offset, mp->me_handle1.vd_length); nextoff = GETNEXTOFF(mp->me_handle1);
if (vp) { mp->me_handle2.vd_offset = nextoff; mp->me_handle2.vd_length = HANDLE_SIZE(tdp2); bcopy(&tdp2->td_handle, (char *)mp + mp->me_handle2.vd_offset, mp->me_handle2.vd_length); nextoff = GETNEXTOFF(mp->me_handle2); }
mp->me_name1.vd_offset = nextoff; mp->me_name1.vd_length = strlen(name1) + 1; bcopy(name1, (char *)mp + mp->me_name1.vd_offset, mp->me_name1.vd_length); nextoff = GETNEXTOFF(mp->me_name1);
mp->me_name2.vd_offset = nextoff; mp->me_name2.vd_length = strlen(name2) + 1; bcopy(name2, (char *)mp + mp->me_name2.vd_offset, mp->me_name2.vd_length); nextoff = GETNEXTOFF(mp->me_name2);
mp->me_roothandle.vd_offset = nextoff; mp->me_roothandle.vd_length = HANDLE_SIZE(tdp3); bcopy(&tdp3->td_handle, (char *)mp + mp->me_roothandle.vd_offset, mp->me_roothandle.vd_length);
mp->me_mode = (vfsp->vfs_flag & VFS_RDONLY ? DM_MOUNT_RDONLY : 0);
/* Queue the message and wait for the reply. */
error = dm_enqueue_mount_event(vfsp, tevp);
/* If no errors occurred, we must leave with the same rights we had upon entry. If errors occurred, we must leave with no rights. */
dm_evt_rele_tevp(tevp, error);
return(error); }
/* Generate an DM_EVENT_UNMOUNT event and wait for a reply. The 'retcode' field indicates whether this is a successful or unsuccessful unmount. If successful, the filesystem is already unmounted, and any pending handle reference to the filesystem will be failed. If the unmount was unsuccessful, then the filesystem will be placed back into full service.
The DM_EVENT_UNMOUNT event should really be asynchronous, because the application has no control over whether or not the unmount succeeds. (The DMAPI spec defined it that way because asynchronous events aren't always guaranteed to be delivered.)
Since the filesystem is already unmounted in the successful case, the DM_EVENT_UNMOUNT event can't make available any vnode to be used in subsequent sid/hanp/hlen/token calls by the application. The event will hang around until the application does a DM_RESP_CONTINUE, but the handle within the event is unusable by the application. */
void dm_send_unmount_event( vfs_t *vfsp, vnode_t *vp, /* NULL if unmount successful */ dm_right_t vfsp_right, mode_t mode, int retcode, /* errno, if unmount failed */ int flags) { dm_namesp_event_t *np; dm_tokevent_t *tevp; dm_tokdata_t *tdp1;
tdp1 = dm_vfs_data(vfsp, vp, vfsp_right);
/* If the unmount failed, put the filesystem back into full service, allowing blocked handle references to finish. If it succeeded, put the filesystem into the DM_STATE_UNMOUNTED state and fail all blocked DM_NO_TOKEN handle accesses. */
if (retcode != 0) { /* unmount was unsuccessful */ dm_change_fsys_entry(vfsp, DM_STATE_MOUNTED); } else { dm_change_fsys_entry(vfsp, DM_STATE_UNMOUNTED); }
/* If the event wasn't in the filesystem dm_eventset_t, just remove the filesystem from the list of DMAPI filesystems and return. */
if (flags & DM_FLAGS_UNWANTED) { if (retcode == 0) dm_remove_fsys_entry(vfsp); return; }
/* Calculate the size of the event in bytes and allocate zeroed memory for it. */
tevp = dm_evt_create_tevp(DM_EVENT_UNMOUNT, HANDLE_SIZE(tdp1), (void **)&np);
dm_add_handle_to_event(tevp, tdp1);
/* Now copy in all the dm_namesp_event_t specific fields. */
np->ne_handle1.vd_offset = sizeof(*np); np->ne_handle1.vd_length = HANDLE_SIZE(tdp1); bcopy(&tdp1->td_handle, (char *) np + np->ne_handle1.vd_offset, np->ne_handle1.vd_length); np->ne_mode = mode; np->ne_retcode = retcode;
/* Since DM_EVENT_UNMOUNT is effectively asynchronous, queue the message and ignore any error return for DM_EVENT_UNMOUNT. */
(void)dm_enqueue_normal_event(vfsp, tevp, flags);
if (retcode == 0) dm_remove_fsys_entry(vfsp);
dm_evt_rele_tevp(tevp, 0); }
/* Generate the given namespace event and wait for a reply (if synchronous) or until the event has been queued (asynchronous). The caller must guarantee that at least one vnode within the filesystem has had its reference count bumped so that the filesystem can't disappear while the event is outstanding. */
int dm_send_namesp_event( dm_eventtype_t event, bhv_desc_t *bdp1, dm_right_t vp1_right, bhv_desc_t *bdp2, dm_right_t vp2_right, char *name1, char *name2, mode_t mode, int retcode, int flags) { dm_namesp_event_t *np; dm_tokevent_t *tevp; dm_tokdata_t *tdp1; /* primary handle for event */ dm_tokdata_t *tdp2 = NULL; /* additional handle for event */ vfs_t *sidvfsp; /* vfs event must be registered on */ size_t nextoff; int error; vnode_t *vp1;
vp1 = BHV_TO_VNODE(bdp1); sidvfsp = vp1->v_vfsp;
switch (event) { case DM_EVENT_PREUNMOUNT: /* * PREUNMOUNT - Send the file system handle in handle1, * and the handle for the root dir in the second. Otherwise * it's a normal sync message; i.e. succeeds or fails * depending on the app's return code. * bdp1 and bdp2 are both the root dir of mounted FS * vp1_right is the filesystem right. * vp2_right is the root inode right. */
tdp1 = dm_vfs_data(sidvfsp, vp1, vp1_right); tdp2 = dm_bhv_data(bdp2, vp2_right, /* reference held */ 1);
if (flags & DM_FLAGS_UNWANTED) { dm_change_fsys_entry(sidvfsp, DM_STATE_UNMOUNTING); return(0); } break;
case DM_EVENT_NOSPACE: /* vp1_right is the filesystem right. */
tdp1 = dm_vfs_data(sidvfsp, vp1, vp1_right); tdp2 = dm_bhv_data(bdp2, vp2_right, /* reference held */ 1); /* additional info - not in the spec */ break;
default: /* All other events only pass in vnodes and don't require any special cases. */
tdp1 = dm_bhv_data(bdp1, vp1_right, /* reference held */ 1); if (bdp2) tdp2 = dm_bhv_data(bdp2, vp2_right, /* reference held */ 1); }
/* Calculate the size of the event in bytes and allocate zeroed memory for it. */
tevp = dm_evt_create_tevp(event, HANDLE_SIZE(tdp1) + (bdp2 ? HANDLE_SIZE(tdp2) : 0) + (name1 ? strlen(name1) + 1 : 0) + (name2 ? strlen(name2) + 1 : 0), (void **)&np);
dm_add_handle_to_event(tevp, tdp1); if (bdp2) dm_add_handle_to_event(tevp, tdp2);
/* Now copy in all the dm_namesp_event_t specific fields. */
np->ne_handle1.vd_offset = sizeof(*np); np->ne_handle1.vd_length = HANDLE_SIZE(tdp1); bcopy(&tdp1->td_handle, (char *) np + np->ne_handle1.vd_offset, np->ne_handle1.vd_length); nextoff = GETNEXTOFF(np->ne_handle1); if (bdp2) { np->ne_handle2.vd_offset = nextoff; np->ne_handle2.vd_length = HANDLE_SIZE(tdp2); bcopy(&tdp2->td_handle, (char *)np + np->ne_handle2.vd_offset, np->ne_handle2.vd_length); nextoff = GETNEXTOFF(np->ne_handle2); } if (name1) { np->ne_name1.vd_offset = nextoff; np->ne_name1.vd_length = strlen(name1) + 1; bcopy(name1, (char *)np + np->ne_name1.vd_offset, np->ne_name1.vd_length); nextoff = GETNEXTOFF(np->ne_name1); } if (name2) { np->ne_name2.vd_offset = nextoff; np->ne_name2.vd_length = strlen(name2) + 1; bcopy(name2, (char *)np + np->ne_name2.vd_offset, np->ne_name2.vd_length); } np->ne_mode = mode; np->ne_retcode = retcode;
/* Queue the message and wait for the reply. */
error = dm_enqueue_normal_event(sidvfsp, tevp, flags);
/* If no errors occurred, we must leave with the same rights we had upon entry. If errors occurred, we must leave with no rights. */
dm_evt_rele_tevp(tevp, error);
if (!error && event == DM_EVENT_PREUNMOUNT) { dm_change_fsys_entry(sidvfsp, DM_STATE_UNMOUNTING); }
return(error); }
/* * Send a message of type "DM_EVENT_USER". Since no vnode is involved, we * don't have to worry about rights here. */
int dm_send_msg( dm_sessid_t targetsid, dm_msgtype_t msgtype, /* SYNC or ASYNC */ size_t buflen, void *bufp) { dm_tokevent_t *tevp; int sync; void *msgp; int error;
if (buflen > DM_MAX_MSG_DATA) return(E2BIG); if (msgtype == DM_MSGTYPE_ASYNC) { sync = 0; } else if (msgtype == DM_MSGTYPE_SYNC) { sync = 1; } else { return(EINVAL); }
tevp = dm_evt_create_tevp(DM_EVENT_USER, buflen, (void **)&msgp);
if (buflen && copy_from_user(msgp, bufp, buflen)) { dm_evt_rele_tevp(tevp, 0); return(EFAULT); }
/* Enqueue the request and wait for the reply. */
error = dm_enqueue_sendmsg_event(targetsid, tevp, sync);
/* Destroy the tevp and return the reply. (dm_pending is not supported here.) */
dm_evt_rele_tevp(tevp, error);
return(error); }
/* * Send a message of type "DM_EVENT_USER". Since no vnode is involved, we * don't have to worry about rights here. */
int dm_create_userevent( dm_sessid_t sid, size_t msglen, void *msgdatap, dm_token_t *tokenp) /* return token created */ { dm_tokevent_t *tevp; dm_token_t token; int error; void *msgp;
if (msglen > DM_MAX_MSG_DATA) return(E2BIG);
tevp = dm_evt_create_tevp(DM_EVENT_USER, msglen, (void **)&msgp);
if (msglen && copy_from_user(msgp, msgdatap, msglen)) { dm_evt_rele_tevp(tevp, 0); return(EFAULT); }
/* Queue the message. If that didn't work, free the tevp structure. */
if ((error = dm_enqueue_user_event(sid, tevp, &token)) != 0) dm_evt_rele_tevp(tevp, 0);
if (!error && copy_to_user(tokenp, &token, sizeof(token))) error = EFAULT;
return(error); }
EXPORT_SYMBOL(dm_send_destroy_event); EXPORT_SYMBOL(dm_send_mount_event); EXPORT_SYMBOL(dm_send_namesp_event); EXPORT_SYMBOL(dm_send_unmount_event); EXPORT_SYMBOL(dm_send_data_event);
|