Re: DiskArbitration, unmounting busy due to fseventsd?
Re: DiskArbitration, unmounting busy due to fseventsd?
- Subject: Re: DiskArbitration, unmounting busy due to fseventsd?
- From: Tim Schooley <email@hidden>
- Date: Mon, 8 Sep 2008 12:47:10 +0100
Hi Terry,
Many thanks for your response.
On Fri, 05 Sep 2008 12:01:58 -0700, Terry Lambert wrote:
> Are you maybe using command line mounts and unmounts other than
> diskutil, which talks to DA? DA will run your command line tools
> under the covers after doing the right things. As long as you go
> through DA to do your mounts and unmount rather than explicit command
> line utilities or programs not going through DA, you should not need
> the nobrowse. As I said before, DA will notify fseventsd to stop
> looking.
All mounts and unmounts are performed via DADiskMountWithArguments and
DADiskUnmount respectively. See below for a code snippet of the unmount
function.
> If Spolight and Time Machine are undesirable, you can explicitly
> disable them programattically by updating settings for "don't look
> here". Pretty sure this is well documented.
Yes - I'm aware that this is possible, but until I've fixed the busy unmount
issue, I didn't see much point looking into this.
So if I can get DADiskUnmount to succeed on mounts to specified locations,
I'd be a super-happy-bunny. It seems though that others are also having
issues: http://zfs.macosforge.org/trac/wiki/faq (search for fseventsd),
although it looks like they're discussing command-line umount.
Below is our unmount function (with some slight changes to make it more
readable without having to add more definitions etc). If you can spot
anything wrong with the way we're approving the unmount, please let me know!
Note that the function is declared in a static class.
Many thanks again for any help.
Kind regards,
Tim
----
/*
Callback context struct.
*/
typedef struct {
bool completed;
int result;
CFRunLoopRef runloop;
bool mount;
} MOUNT_RESULT;
/*
Generic callback function for mounts and unmounts.
*/
static void
mount_disk_da_callback(
DADiskRef /*disk*/,
DADissenterRef dissenter,
void* context
) {
DAReturn rc;
MOUNT_RESULT* result = static_cast<MOUNT_RESULT*>(context);
if (NULL == result) {
LOG_ERR("Failed to obtain context during DA callback.");
goto out; // Should never happen.
}
if (NULL == dissenter) goto out;
rc = DADissenterGetStatus(dissenter);
switch (rc) {
/* error handling that sets result.result */
}
out:
CFRunLoopStop(result->runloop);
result->completed = true;
}
/*
Unmount approval callback. We accept by returning NULL.
*/
static
DADissenterRef
approve_unmount_da_callback(
DADiskRef /*disk*/,
void* /*context*/
) {
LOG_DEBUG("approve_unmount_da_callback(): approving unmount.");
return NULL;
}
/*
Unmount function.
*/
int
Mounter::unmount(
const char* device_path,
const bool& force
) {
int result = 0;
DADiskRef disk_ref = NULL;
DASessionRef session_ref = NULL;
DAApprovalSessionRef app_session_ref = NULL;
MOUNT_RESULT unmount_result;
unmount_result.completed = false;
unmount_result.result = 0;
unmount_result.mount = false;
// Create DA session.
session_ref = DASessionCreate(kCFAllocatorDefault);
if (NULL == session_ref) {
LOG_ERR("Failed to create DA session during unmount.");
result = ERR_UNMOUNT;
goto out;
}
// Create DA approval session.
app_session_ref = DAApprovalSessionCreate(kCFAllocatorDefault);
if (NULL == app_session_ref) {
LOG_ERR("Failed to create DA approval session during unmount.");
result = ERR_UMOUNT;
goto out;
}
// Grab the current runloop and add it to the struct.
unmount_result.runloop = CFRunLoopGetCurrent();
CFRetain(unmount_result.runloop);
// Register our unmount approval callback.
DARegisterDiskUnmountApprovalCallback(
app_session_ref,
kDADiskDescriptionMatchVolumeMountable,
approve_unmount_da_callback,
NULL);
// Add our DA session to the runloop.
DASessionScheduleWithRunLoop(session_ref,
//CFRunLoopGetCurrent(),
unmount_result.runloop,
kCFRunLoopDefaultMode);
// Add our DA approval session to the runloop.
DAApprovalSessionScheduleWithRunLoop(app_session_ref,
unmount_result.runloop,
kCFRunLoopDefaultMode);
// Get a reference to the disk, using the disk name.
disk_ref = DADiskCreateFromBSDName(kCFAllocatorDefault,
session_ref,
device_path);
if (NULL == disk_ref) {
LOG_ERR("Failed to create DA disk reference during unmount.");
result = ERR_UNMOUNT;
goto out;
}
// Actually call the DA service to unmount the disk
DADiskUnmountOptions options =
force ? kDADiskUnmountOptionForce : kDADiskUnmountOptionDefault;
DADiskUnmount(disk_ref,
options,
&mount_disk_da_callback,
&unmount_result);
LOG_DEBUG("Waiting for unmount callback from DA service...");
(void)CFRunLoopRun();
CFRelease(unmount_result.runloop);
if (0 != (result = unmount_result.result)) {
LOG_ERR("The DA service failed to unmount the device [%s].",
error_str(unmount_result.result));
goto out;
}
LOG_DEBUG("unmount successful");
out:
if (NULL != session_ref) {
DASessionUnscheduleFromRunLoop(session_ref,
CFRunLoopGetCurrent(),
kCFRunLoopDefaultMode);
CFRelease(session_ref);
}
if (NULL != app_session_ref) {
DAUnregisterApprovalCallback(app_session_ref,
(void*)approve_unmount_da_callback,
NULL);
DAApprovalSessionUnscheduleFromRunLoop(app_session_ref,
CFRunLoopGetCurrent(),
kCFRunLoopDefaultMode);
CFRelease(app_session_ref);
}
if (NULL != disk_ref) CFRelease(disk_ref);
return result;
}
----
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden