AppleLVMStorageRequest.cpp   [plain text]


/*
 * Copyright (c) 2001-2007 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 *
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * @APPLE_LICENSE_HEADER_END@
 */

#include "AppleRAID.h"

#define super AppleRAIDStorageRequest
OSDefineMetaClassAndStructors(AppleLVMStorageRequest, AppleRAIDStorageRequest);


AppleLVMStorageRequest * AppleLVMStorageRequest::withAppleRAIDSet(AppleRAIDSet *set)
{
    AppleLVMStorageRequest *storageRequest = new AppleLVMStorageRequest;
    
    if (storageRequest != 0) {
        if (!storageRequest->initWithAppleRAIDSet(set)) {
            storageRequest->release();
            storageRequest = 0;
        }
    }
    
    return storageRequest;
}


void AppleLVMStorageRequest::read(IOService *client, UInt64 byteStart, IOMemoryDescriptor *buffer,
				  IOStorageAttributes *attributes, IOStorageCompletion *completion)
{
    AppleRAIDMember		*member;
    IOStorageCompletion		storageCompletion;
    AppleRAIDMemoryDescriptor	*memoryDescriptor;
    
    srClient			= client;
    srClientsCompletion 	= *completion;
    srCompletedCount		= 0;
    srMemoryDescriptor 		= buffer;
    srMemoryDescriptorDirection	= buffer->getDirection();
    srByteCount 		= buffer->getLength();
    srByteStart			= byteStart;

    storageCompletion.target    = srEventSource;
    storageCompletion.action    = srEventSource->getStorageCompletionActionLVG();

    // only handle lv
    AppleLVMVolume * lv = OSDynamicCast(AppleLVMVolume, client);
    if (!lv) {
	IOLog("AppleLVMStorageRequest::read() received a non-lvm request?\n");
        IOStorage::complete(completion, kIOReturnInternalError, 0);
	return;
    }

    // XXXSNAP
    if (lv->getTypeID() == kLVMTypeSnapRO) {
	lv = lv->parentVolume();    // XXX hack
	assert(lv);
    }

    /*	    
	each storage request has a fixed number of descriptors, if we need more than
	that just recycle the current storage request (this)
    */
    
    UInt64 requestSize = srByteCount;
    UInt64 requestStart = srByteStart;
    UInt32 requestCountMax = srRAIDSet->getMaxRequestCount();
    srRequestCount = 0;

    IOLogRW(" lvm read (%u)  requestStart %llu requestSize %llu\n", (uint32_t)srRequestCount, requestStart, requestSize);

    while (requestSize && srRequestCount < requestCountMax) {

	memoryDescriptor = srMemoryDescriptors[srRequestCount];
	assert(memoryDescriptor);

	if (!memoryDescriptor->configureForMemoryDescriptor(buffer, requestStart, requestSize, lv)) {

	    IOLog(" lvm read configure failed\n");
	    
	    // XXX set length to zero?

	    break;
	}

	requestStart += memoryDescriptor->getLength();
	requestSize -= memoryDescriptor->getLength();
	srRequestCount++;
	
	IOLogRW(" lvm read (%u)  requestStart %llu requestSize %llu\n", (uint32_t)srRequestCount, requestStart, requestSize);
    }

    if (requestSize) {

	if (srRequestCount < requestCountMax) {

	    // XXX something went very wrong

	    IOLog(" lvm read failed #1, srByteStart %llu srByteCount %llu srRequestCount %u requestStart %llu requestSize %llu\n",
		  srByteStart, srByteCount, (uint32_t)srRequestCount, requestStart, requestSize);

	    IOStorage::complete(completion, kIOReturnInternalError, 0);
	    return;
	}

	// XXX set storageCompletion to reschedule more i/o;
	// srBytesScheduled  ??

	IOLog(" lvm read failed #2, srByteStart %llu srByteCount %llu srRequestCount %u requestStart %llu requestSize %llu\n",
	      srByteStart, srByteCount, (uint32_t)srRequestCount, requestStart, requestSize);

        IOStorage::complete(completion, kIOReturnInternalError, 0);
	return;
    }

    assert(srMemberBaseOffset == 0);

    // second pass, kick off the i/o's if device exists

    UInt32 i;
    for (i=0; i < srRequestCount; i++) {

	memoryDescriptor = srMemoryDescriptors[i];
	storageCompletion.parameter = memoryDescriptor;

	member = srRAIDSet->arMembers[memoryDescriptor->mdMemberIndex];

	if (member) {
	    storageCompletion.parameter = memoryDescriptor;
	    member->read(srRAIDSet, memoryDescriptor->mdMemberByteStart, memoryDescriptor, attributes, &storageCompletion);
	} else {
	    srEventSource->completeRequest(memoryDescriptor, kIOReturnSuccess, 0);   // no bytes & no error in completion
	}
    }
}


// XXX the read and write code is almost the same, could merge them together?


void AppleLVMStorageRequest::write(IOService * client, UInt64 byteStart, IOMemoryDescriptor *buffer,
				   IOStorageAttributes *attributes, IOStorageCompletion *completion)
{
    AppleRAIDMember		*member;
    IOStorageCompletion		storageCompletion;
    AppleRAIDMemoryDescriptor	*memoryDescriptor;
    
    srClient			= client;
    srClientsCompletion 	= *completion;
    srCompletedCount		= 0;
    srMemoryDescriptor 		= buffer;
    srMemoryDescriptorDirection	= buffer->getDirection();
    srByteCount 		= buffer->getLength();
    srByteStart			= byteStart;

    storageCompletion.target    = srEventSource;
    storageCompletion.action    = srEventSource->getStorageCompletionActionLVG();

    // only handle lv
    AppleLVMVolume * lv = OSDynamicCast(AppleLVMVolume, client);
    if (!lv) {
	IOLog("AppleLVMStorageRequest::write() received a non-lvm request?\n");
        IOStorage::complete(completion, kIOReturnInternalError, 0);
	return;
    }

    // XXXSNAP
    if (lv->getTypeID() == kLVMTypeSnapRO) {
	lv = lv->parentVolume();    // XXX hack
	assert(lv);
    }

    /*	    
	each storage request has a fixed number of descriptors, if we need more than
	that just recycle the current storage request (this)
    */
    
    UInt64 requestSize = srByteCount;
    UInt64 requestStart = srByteStart;
    UInt32 requestCountMax = srRAIDSet->getMaxRequestCount();
    srRequestCount = 0;

    IOLogRW(" lvm write (%u) requestStart %llu requestSize %llu\n", (uint32_t)srRequestCount, requestStart, requestSize);
    
    while (requestSize && srRequestCount < requestCountMax) {

	memoryDescriptor = srMemoryDescriptors[srRequestCount];
	assert(memoryDescriptor);

	if (!memoryDescriptor->configureForMemoryDescriptor(buffer, requestStart, requestSize, lv)) {

	    IOLog(" lvm write configure failed\n");

	    // XXX set length to zero?

	    break;
	}

	requestStart += memoryDescriptor->getLength();
	requestSize -= memoryDescriptor->getLength();
	srRequestCount++;

	IOLogRW(" lvm write (%u) requestStart %llu requestSize %llu\n", (uint32_t)srRequestCount, requestStart, requestSize);
    }

    if (requestSize) {

	if (srRequestCount < requestCountMax) {

	    // XXX something went very wrong

	    IOLog(" lvm write failed #1, srByteStart %llu srByteCount %llu srRequestCount %u requestStart %llu requestSize %llu\n",
		  srByteStart, srByteCount, (uint32_t)srRequestCount, requestStart, requestSize);

	    IOStorage::complete(completion, kIOReturnInternalError, 0);
	    return;
	}

	// XXX set storageCompletion to reschedule more i/o;
	// srBytesScheduled  ??

	IOLog(" lvm write failed #2, srByteStart %llu srByteCount %llu srRequestCount %u requestStart %llu requestSize %llu\n",
	      srByteStart, srByteCount, (uint32_t)srRequestCount, requestStart, requestSize);

        IOStorage::complete(completion, kIOReturnInternalError, 0);
	return;
    }

//	IOLog(" lvm write   extent %p offset %llu byteStart %llu\n", extent, extent->lvExtentGroupOffset, srByteStart);

    assert(srMemberBaseOffset == 0);

    // second pass, kick off the i/o's if device exists

    UInt32 i;
    for (i=0; i < srRequestCount; i++) {

	memoryDescriptor = srMemoryDescriptors[i];
	storageCompletion.parameter = memoryDescriptor;

	member = srRAIDSet->arMembers[memoryDescriptor->mdMemberIndex];

	if (member) {
	    storageCompletion.parameter = memoryDescriptor;
	    member->write(srRAIDSet, memoryDescriptor->mdMemberByteStart, memoryDescriptor, attributes, &storageCompletion);
	} else {
	    srEventSource->completeRequest(memoryDescriptor, kIOReturnSuccess, 0);   // no bytes & no error in completion
	}
    }
}