|
|
1.1 root 1: /*
2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22:
23: #include <IOKit/storage/IOPartitionScheme.h>
24:
25: #define super IOStorage
26: OSDefineMetaClassAndStructors(IOPartitionScheme, IOStorage)
27:
28: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
29:
30: bool IOPartitionScheme::init(OSDictionary * properties = 0)
31: {
32: //
33: // Initialize this object's minimal state.
34: //
35:
36: if (super::init(properties) == false) return false;
37:
38: _openLevel = kAccessNone;
39: _openReaders = OSSet::withCapacity(16);
40: _openReaderWriters = OSSet::withCapacity(16);
41:
42: if (_openReaders == 0 || _openReaderWriters == 0) return false;
43:
44: return true;
45: }
46:
47: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
48:
49: void IOPartitionScheme::free()
50: {
51: //
52: // Free all of this object's outstanding resources.
53: //
54:
55: if (_openReaders) _openReaders->release();
56: if (_openReaderWriters) _openReaderWriters->release();
57:
58: super::free();
59: }
60:
61: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62:
63: bool IOPartitionScheme::handleOpen(IOService * client,
64: IOOptionBits options,
65: void * argument)
66: {
67: //
68: // The handleOpen method grants or denies permission to access this object
69: // to an interested client. The argument is an IOStorageAccess value that
70: // specifies the level of access desired -- reader or reader-writer.
71: //
72: // This method can be invoked to upgrade or downgrade the access level for
73: // an existing client as well. The previous access level will prevail for
74: // upgrades that fail, of course. A downgrade should never fail. If the
75: // new access level should be the same as the old for a given client, this
76: // method will do nothing and return success. In all cases, one, singular
77: // close-per-client is expected for all opens-per-client received.
78: //
79: // This implementation replaces the IOService definition of handleOpen().
80: //
81: // We are guaranteed that no other opens or closes will be processed until
82: // we make our decision, change our state, and return from this method.
83: //
84:
85: IOStorageAccess access = (IOStorageAccess) (int) argument;
86: IOStorageAccess level;
87:
88: assert(client);
89: assert(access == kAccessReader || access == kAccessReaderWriter);
90:
91: //
92: // A partition scheme multiplexes the opens it receives from several clients
93: // and sends one open to the level below that satisfies the highest level of
94: // access.
95: //
96:
97: unsigned writers = _openReaderWriters->getCount();
98:
99: if (_openReaderWriters->containsObject(client)) writers--;
100: if (access == kAccessReaderWriter) writers++;
101:
102: level = (writers) ? kAccessReaderWriter : kAccessReader;
103:
104: //
105: // Determine whether the levels below us accept this open or not (we avoid
106: // the open if the required access is the access we already hold).
107: //
108:
109: if (_openLevel != level) // (has open level changed?)
110: {
111: IOStorage * provider = OSDynamicCast(IOStorage, getProvider());
112:
113: if (provider && provider->open(this, options, level) == false)
114: return false;
115: }
116:
117: //
118: // Process the open.
119: //
120:
121: if (access == kAccessReader)
122: {
123: _openReaders->setObject(client);
124:
125: _openReaderWriters->removeObject(client); // (for a downgrade)
126: }
127: else // (access == kAccessReaderWriter)
128: {
129: _openReaderWriters->setObject(client);
130:
131: _openReaders->removeObject(client); // (for an upgrade)
132: }
133:
134: _openLevel = level;
135:
136: return true;
137: }
138:
139: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
140:
141: bool IOPartitionScheme::handleIsOpen(const IOService * client) const
142: {
143: //
144: // The handleIsOpen method determines whether the specified client, or any
145: // client if none is specificed, presently has an open on this object.
146: //
147: // This implementation replaces the IOService definition of handleIsOpen().
148: //
149: // We are guaranteed that no other opens or closes will be processed until
150: // we return from this method.
151: //
152:
153: if (client == 0) return (_openLevel != kAccessNone);
154:
155: return ( _openReaderWriters->containsObject(client) ||
156: _openReaders->containsObject(client) );
157: }
158:
159: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
160:
161: void IOPartitionScheme::handleClose(IOService * client, IOOptionBits options)
162: {
163: //
164: // The handleClose method closes the client's access to this object.
165: //
166: // This implementation replaces the IOService definition of handleClose().
167: //
168: // We are guaranteed that no other opens or closes will be processed until
169: // we change our state and return from this method.
170: //
171:
172: assert(client);
173:
174: //
175: // Process the close.
176: //
177:
178: if (_openReaderWriters->containsObject(client)) // (is it a reader-writer?)
179: {
180: _openReaderWriters->removeObject(client);
181: }
182: else if (_openReaders->containsObject(client)) // (is the client a reader?)
183: {
184: _openReaders->removeObject(client);
185: }
186: else // (is the client is an imposter?)
187: {
188: assert(0);
189: return;
190: }
191:
192: //
193: // Reevaluate the open we have on the level below us. If no opens remain,
194: // we close, or if no reader-writer remains, but readers do, we downgrade.
195: //
196:
197: IOStorageAccess level;
198:
199: if (_openReaderWriters->getCount()) level = kAccessReaderWriter;
200: else if (_openReaders->getCount()) level = kAccessReader;
201: else level = kAccessNone;
202:
203: if (_openLevel != level) // (has open level changed?)
204: {
205: IOStorage * provider = OSDynamicCast(IOStorage, getProvider());
206:
207: assert(level != kAccessReaderWriter);
208:
209: if (provider)
210: {
211: if (level == kAccessNone) // (is a close in order?)
212: {
213: provider->close(this, options);
214: }
215: else // (is a downgrade in order?)
216: {
217: bool success;
218: success = provider->open(this, 0, level);
219: assert(success); // (should never fail, unless avoided deadlock)
220: }
221: }
222:
223: _openLevel = level; // (set new open level)
224: }
225: }
226:
227: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
228:
229: void IOPartitionScheme::read(IOService * /* client */,
230: UInt64 byteStart,
231: IOMemoryDescriptor * buffer,
232: IOStorageCompletion completion)
233: {
234: //
235: // Read data from the storage object at the specified byte offset into the
236: // specified buffer, asynchronously. When the read completes, the caller
237: // will be notified via the specified completion action.
238: //
239: // The buffer will be retained for the duration of the read.
240: //
241: // For simple partition schemes, the default behavior is to simply pass the
242: // read through to the provider media. More complex partition schemes such
243: // as RAID will need to do extra processing here.
244: //
245:
246: getProvider()->read(this, byteStart, buffer, completion);
247: }
248:
249: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
250:
251: void IOPartitionScheme::write(IOService * /* client */,
252: UInt64 byteStart,
253: IOMemoryDescriptor * buffer,
254: IOStorageCompletion completion)
255: {
256: //
257: // Write data into the storage object at the specified byte offset from the
258: // specified buffer, asynchronously. When the write completes, the caller
259: // will be notified via the specified completion action.
260: //
261: // The buffer will be retained for the duration of the write.
262: //
263: // For simple partition schemes, the default behavior is to simply pass the
264: // write through to the provider media. More complex partition schemes such
265: // as RAID will need to do extra processing here.
266: //
267:
268: getProvider()->write(this, byteStart, buffer, completion);
269: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.