xref: /haiku/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp (revision 260e077ff7d1bb76c5badef636955857cae465db)
1 /*
2  * Copyright 2003-2008, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold, bonefish@cs.tu-berlin.de
7  *		Axel Dörfler, axeld@pinc-software.de
8  */
9 
10 /*! \file ddm_userland_interface.cpp
11 
12  	\brief Interface for userspace calls.
13 */
14 
15 #include <stdlib.h>
16 
17 #include <AutoDeleter.h>
18 #include <ddm_userland_interface.h>
19 #include <fs/KPath.h>
20 #include <KDiskDevice.h>
21 #include <KDiskDeviceManager.h>
22 #include <KDiskDeviceUtils.h>
23 #include <KDiskSystem.h>
24 #include <KFileDiskDevice.h>
25 #include <syscall_args.h>
26 
27 #include "UserDataWriter.h"
28 
29 using namespace BPrivate::DiskDevice;
30 
31 // debugging
32 #define ERROR(x)
33 
34 
35 // TODO: Replace all instances, when it has been decided how to handle
36 // notifications during jobs.
37 #define DUMMY_JOB_ID	0
38 
39 
40 // TODO: Add user address checks and check return values of user_memcpy()!
41 
42 
43 // ddm_strlcpy
44 /*! \brief Wrapper around user_strlcpy() that returns a status_t
45 	indicating appropriate success or failure.
46 
47 	\param allowTruncation If \c true, does not return an error if
48 	       \a from is longer than \to. If \c false, returns \c B_NAME_TOO_LONG
49 	       if \a from is longer than \to.
50 */
51 static status_t
52 ddm_strlcpy(char *to, const char *from, size_t size,
53 	bool allowTruncation = false)
54 {
55 	ssize_t fromLen = user_strlcpy(to, from, size);
56 	if (fromLen < 0)
57 		return fromLen;
58 	if ((size_t)fromLen >= size && !allowTruncation)
59 		return B_NAME_TOO_LONG;
60 	return B_OK;
61 }
62 
63 
64 // copy_from_user_value
65 template<typename Type>
66 static inline status_t
67 copy_from_user_value(Type& value, const Type* userValue)
68 {
69 	if (!userValue)
70 		return B_BAD_VALUE;
71 
72 	if (!IS_USER_ADDRESS(userValue))
73 		return B_BAD_ADDRESS;
74 
75 	return user_memcpy(&value, userValue, sizeof(Type));
76 }
77 
78 
79 // copy_to_user_value
80 template<typename Type>
81 static inline status_t
82 copy_to_user_value(Type* userValue, const Type& value)
83 {
84 	if (!userValue)
85 		return B_BAD_VALUE;
86 
87 	if (!IS_USER_ADDRESS(userValue))
88 		return B_BAD_ADDRESS;
89 
90 	return user_memcpy(userValue, &value, sizeof(Type));
91 }
92 
93 
94 // UserStringParameter
95 template<bool kAllowsNull>
96 struct UserStringParameter {
97 	char*	value;
98 
99 	inline UserStringParameter()
100 		: value(NULL)
101 	{
102 	}
103 
104 	inline ~UserStringParameter()
105 	{
106 		free(value);
107 	}
108 
109 	inline status_t Init(const char* userValue, size_t maxSize)
110 	{
111 		if (userValue == NULL) {
112 			if (!kAllowsNull)
113 				return B_BAD_VALUE;
114 
115 			return B_OK;
116 		}
117 
118 		if (!IS_USER_ADDRESS(userValue))
119 			return B_BAD_ADDRESS;
120 
121 		value = (char*)malloc(maxSize);
122 		if (value == NULL)
123 			return B_NO_MEMORY;
124 
125 		ssize_t bytesCopied = user_strlcpy(value, userValue, maxSize);
126 		if (bytesCopied < 0)
127 			return bytesCopied;
128 
129 		if ((size_t)bytesCopied >= maxSize)
130 			return B_BUFFER_OVERFLOW;
131 
132 		return B_OK;
133 	}
134 
135 	inline operator const char*()
136 	{
137 		return value;
138 	}
139 
140 	inline operator char*()
141 	{
142 		return value;
143 	}
144 };
145 
146 
147 // UserMemoryParameter
148 template<typename Type, bool kAllowsNull>
149 struct UserMemoryParameter {
150 	Type*	value;
151 
152 	inline UserMemoryParameter()
153 		: value(NULL)
154 	{
155 	}
156 
157 	inline ~UserMemoryParameter()
158 	{
159 		free(value);
160 	}
161 
162 	inline status_t Init(const Type* userValue, size_t size)
163 	{
164 		if (userValue == NULL) {
165 			if (!kAllowsNull)
166 				return B_BAD_VALUE;
167 
168 			value = NULL;
169 			return B_OK;
170 		}
171 
172 		if (!IS_USER_ADDRESS(userValue))
173 			return B_BAD_ADDRESS;
174 
175 		value = (Type*)malloc(size);
176 		if (value == NULL)
177 			return B_NO_MEMORY;
178 
179 		return user_memcpy(value, userValue, size);
180 	}
181 
182 	inline status_t Init(const Type* userValue, size_t size, size_t maxSize)
183 	{
184 		if (size > maxSize)
185 			return B_BAD_VALUE;
186 
187 		return Init(userValue, size);
188 	}
189 };
190 
191 
192 #if 0
193 // move_descendants
194 static void
195 move_descendants(KPartition *partition, off_t moveBy)
196 {
197 	if (!partition)
198 		return;
199 	partition->SetOffset(partition->Offset() + moveBy);
200 	// move children
201 	for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++)
202 		move_descendants(child, moveBy);
203 }
204 
205 
206 // move_descendants_contents
207 static status_t
208 move_descendants_contents(KPartition *partition)
209 {
210 	if (!partition)
211 		return B_BAD_VALUE;
212 	// implicit content disk system changes
213 	KDiskSystem *diskSystem = partition->DiskSystem();
214 	if (diskSystem || partition->AlgorithmData()) {
215 		status_t error = diskSystem->ShadowPartitionChanged(partition,
216 			NULL, B_PARTITION_MOVE);
217 		if (error != B_OK)
218 			return error;
219 	}
220 	// move children's contents
221 	for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++) {
222 		status_t error = move_descendants_contents(child);
223 		if (error != B_OK)
224 			return error;
225 	}
226 	return B_OK;
227 }
228 #endif // 0
229 
230 
231 // _user_get_next_disk_device_id
232 partition_id
233 _user_get_next_disk_device_id(int32 *_cookie, size_t *neededSize)
234 {
235 	if (!_cookie)
236 		return B_BAD_VALUE;
237 	int32 cookie;
238 	user_memcpy(&cookie, _cookie, sizeof(cookie));
239 
240 	partition_id id = B_ENTRY_NOT_FOUND;
241 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
242 	// get the next device
243 	if (KDiskDevice *device = manager->RegisterNextDevice(&cookie)) {
244 		PartitionRegistrar _(device, true);
245 		id = device->ID();
246 		if (neededSize) {
247 			if (DeviceReadLocker locker = device) {
248 				// get the needed size
249 				UserDataWriter writer;
250 				device->WriteUserData(writer);
251 				status_t status = copy_to_user_value(neededSize,
252 					writer.AllocatedSize());
253 				if (status != B_OK)
254 					return status;
255 			} else {
256 				id = B_ERROR;
257 			}
258 		}
259 	}
260 	user_memcpy(_cookie, &cookie, sizeof(cookie));
261 	return id;
262 }
263 
264 
265 // _user_find_disk_device
266 partition_id
267 _user_find_disk_device(const char *_filename, size_t *neededSize)
268 {
269 	UserStringParameter<false> filename;
270 	status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
271 	if (error != B_OK)
272 		return error;
273 
274 	partition_id id = B_ENTRY_NOT_FOUND;
275 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
276 	// find the device
277 	if (KDiskDevice *device = manager->RegisterDevice(filename)) {
278 		PartitionRegistrar _(device, true);
279 		id = device->ID();
280 		if (neededSize) {
281 			if (DeviceReadLocker locker = device) {
282 				// get the needed size
283 				UserDataWriter writer;
284 				device->WriteUserData(writer);
285 				error = copy_to_user_value(neededSize, writer.AllocatedSize());
286 				if (error != B_OK)
287 					return error;
288 			} else
289 				return B_ERROR;
290 		}
291 	}
292 	return id;
293 }
294 
295 
296 // _user_find_partition
297 partition_id
298 _user_find_partition(const char *_filename, size_t *neededSize)
299 {
300 	UserStringParameter<false> filename;
301 	status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
302 	if (error != B_OK)
303 		return error;
304 
305 	partition_id id = B_ENTRY_NOT_FOUND;
306 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
307 	// find the partition
308 	if (KPartition *partition = manager->RegisterPartition(filename)) {
309 		PartitionRegistrar _(partition, true);
310 		id = partition->ID();
311 		if (neededSize) {
312 			// get and lock the partition's device
313 			KDiskDevice *device = manager->RegisterDevice(partition->ID(),
314 				false);
315 			if (!device)
316 				return B_ENTRY_NOT_FOUND;
317 			PartitionRegistrar _2(device, true);
318 			if (DeviceReadLocker locker = device) {
319 				// get the needed size
320 				UserDataWriter writer;
321 				device->WriteUserData(writer);
322 				error = copy_to_user_value(neededSize, writer.AllocatedSize());
323 				if (error != B_OK)
324 					return error;
325 			} else
326 				return B_ERROR;
327 		}
328 	}
329 	return id;
330 }
331 
332 
333 partition_id
334 _user_find_file_disk_device(const char *_filename, size_t *neededSize)
335 {
336 	UserStringParameter<false> filename;
337 	status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
338 	if (error != B_OK)
339 		return error;
340 
341 	KPath path(filename, true);
342 
343 	partition_id id = B_ENTRY_NOT_FOUND;
344 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
345 	// find the device
346 	if (KFileDiskDevice* device = manager->RegisterFileDevice(path.Path())) {
347 		PartitionRegistrar _(device, true);
348 		id = device->ID();
349 		if (neededSize) {
350 			if (DeviceReadLocker locker = device) {
351 				// get the needed size
352 				UserDataWriter writer;
353 				device->WriteUserData(writer);
354 				error = copy_to_user_value(neededSize, writer.AllocatedSize());
355 				if (error != B_OK)
356 					return error;
357 			} else
358 				return B_ERROR;
359 		}
360 	}
361 	return id;
362 }
363 
364 
365 // _user_get_disk_device_data
366 /*!	\brief Writes data describing the disk device identified by ID and all
367 		   its partitions into the supplied buffer.
368 
369 	The function passes the buffer size required to hold the data back
370 	through the \a _neededSize parameter, if the device could be found at
371 	least and no serious error occured. If fails with \c B_BUFFER_OVERFLOW,
372 	if the supplied buffer is too small or a \c NULL buffer is supplied
373 	(and \c bufferSize is 0).
374 
375 	The device is identified by \a id. If \a deviceOnly is \c true, then
376 	it must be the ID of a disk device, otherwise the disk device is
377 	chosen, on which the partition \a id refers to resides.
378 
379 	\param id The ID of an arbitrary partition on the disk device (including
380 		   the disk device itself), whose data shall be returned
381 		   (if \a deviceOnly is \c false), or the ID of the disk device
382 		   itself (if \a deviceOnly is true).
383 	\param deviceOnly Specifies whether only IDs of disk devices (\c true),
384 		   or also IDs of partitions (\c false) are accepted for \a id.
385 	\param buffer The buffer into which the disk device data shall be written.
386 		   May be \c NULL.
387 	\param bufferSize The size of \a buffer.
388 	\param _neededSize Pointer to a variable into which the actually needed
389 		   buffer size is written. May be \c NULL.
390 	\return
391 	- \c B_OK: Everything went fine. The device was found and, if not \c NULL,
392 	  in \a _neededSize the actually needed buffer size is returned. And
393 	  \a buffer will contain the disk device data.
394 	- \c B_BAD_VALUE: \c NULL \a buffer, but not 0 \a bufferSize.
395 	- \c B_BUFFER_OVERFLOW: The supplied buffer was too small. \a _neededSize,
396 	  if not \c NULL, will contain the required buffer size.
397 	- \c B_NO_MEMORY: Insufficient memory to complete the operation.
398 	- \c B_ENTRY_NOT_FOUND: \a id is no valid disk device ID (if \a deviceOnly
399 	  is \c true) or not even a valid partition ID (if \a deviceOnly is
400 	  \c false).
401 	- \c B_ERROR: An unexpected error occured.
402 	- another error code...
403 */
404 status_t
405 _user_get_disk_device_data(partition_id id, bool deviceOnly,
406 	user_disk_device_data *buffer, size_t bufferSize, size_t *_neededSize)
407 {
408 	if (!buffer && bufferSize > 0)
409 		return B_BAD_VALUE;
410 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
411 	// get the device
412 	if (KDiskDevice *device = manager->RegisterDevice(id, deviceOnly)) {
413 		PartitionRegistrar _(device, true);
414 		if (DeviceReadLocker locker = device) {
415 			// do a dry run first to get the needed size
416 			UserDataWriter writer;
417 			device->WriteUserData(writer);
418 			size_t neededSize = writer.AllocatedSize();
419 			if (_neededSize) {
420 				status_t error = copy_ref_var_to_user(neededSize, _neededSize);
421 				if (error != B_OK)
422 					return error;
423 			}
424 			// if no buffer has been supplied or the buffer is too small,
425 			// then we're done
426 			if (!buffer || bufferSize < neededSize)
427 				return B_BUFFER_OVERFLOW;
428 			// otherwise allocate a kernel buffer
429 			user_disk_device_data *kernelBuffer
430 				= static_cast<user_disk_device_data*>(malloc(neededSize));
431 			if (!kernelBuffer)
432 				return B_NO_MEMORY;
433 			MemoryDeleter deleter(kernelBuffer);
434 			// write the device data into the buffer
435 			writer.SetTo(kernelBuffer, bufferSize);
436 			device->WriteUserData(writer);
437 			// sanity check
438 			if (writer.AllocatedSize() != neededSize) {
439 				ERROR(("Size of written disk device user data changed from "
440 					   "%lu to %lu while device was locked!\n"));
441 				return B_ERROR;
442 			}
443 			// relocate
444 			status_t error = writer.Relocate(buffer);
445 			if (error != B_OK)
446 				return error;
447 			// copy out
448 			if (buffer)
449 				return user_memcpy(buffer, kernelBuffer, neededSize);
450 		} else
451 			return B_ERROR;
452 	}
453 	return B_ENTRY_NOT_FOUND;
454 }
455 
456 
457 // _user_register_file_device
458 partition_id
459 _user_register_file_device(const char *_filename)
460 {
461 	UserStringParameter<false> filename;
462 	status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
463 	if (error != B_OK)
464 		return error;
465 
466 	KPath path(filename, true);
467 
468 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
469 	if (ManagerLocker locker = manager) {
470 		if (KFileDiskDevice *device = manager->FindFileDevice(path.Path()))
471 			return device->ID();
472 		return manager->CreateFileDevice(path.Path());
473 	}
474 	return B_ERROR;
475 }
476 
477 
478 // _user_unregister_file_device
479 status_t
480 _user_unregister_file_device(partition_id deviceID, const char *_filename)
481 {
482 	if (deviceID < 0 && !_filename)
483 		return B_BAD_VALUE;
484 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
485 	if (deviceID >= 0) {
486 		return manager->DeleteFileDevice(deviceID);
487 	} else {
488 		UserStringParameter<false> filename;
489 		status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
490 		if (error != B_OK)
491 			return error;
492 
493 		return manager->DeleteFileDevice(filename);
494 	}
495 }
496 
497 
498 status_t
499 _user_get_file_disk_device_path(partition_id id, char* buffer,
500 	size_t bufferSize)
501 {
502 	if (id < 0 || buffer == NULL || bufferSize == 0)
503 		return B_BAD_VALUE;
504 
505 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
506 
507 	if (KDiskDevice *device = manager->RegisterDevice(id, true)) {
508 		PartitionRegistrar _(device, true);
509 		if (DeviceReadLocker locker = device) {
510 			KFileDiskDevice* fileDevice
511 				= dynamic_cast<KFileDiskDevice*>(device);
512 			if (fileDevice == NULL)
513 				return B_BAD_VALUE;
514 
515 			return user_strlcpy(buffer, fileDevice->FilePath(), bufferSize);
516 		}
517 	}
518 
519 	return B_ERROR;
520 }
521 
522 
523 // _user_get_disk_system_info
524 status_t
525 _user_get_disk_system_info(disk_system_id id, user_disk_system_info *_info)
526 {
527 	if (!_info)
528 		return B_BAD_VALUE;
529 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
530 	if (ManagerLocker locker = manager) {
531 		if (KDiskSystem *diskSystem = manager->FindDiskSystem(id)) {
532 			user_disk_system_info info;
533 			diskSystem->GetInfo(&info);
534 			user_memcpy(_info, &info, sizeof(info));
535 			return B_OK;
536 		}
537 	}
538 	return B_ENTRY_NOT_FOUND;
539 }
540 
541 
542 // _user_get_next_disk_system_info
543 status_t
544 _user_get_next_disk_system_info(int32 *_cookie, user_disk_system_info *_info)
545 {
546 	if (!_cookie || !_info)
547 		return B_BAD_VALUE;
548 	int32 cookie;
549 	user_memcpy(&cookie, _cookie, sizeof(cookie));
550 	status_t result = B_ENTRY_NOT_FOUND;
551 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
552 	if (ManagerLocker locker = manager) {
553 		if (KDiskSystem *diskSystem = manager->NextDiskSystem(&cookie)) {
554 			user_disk_system_info info;
555 			diskSystem->GetInfo(&info);
556 			user_memcpy(_info, &info, sizeof(info));
557 			result = B_OK;
558 		}
559 	}
560 	user_memcpy(_cookie, &cookie, sizeof(cookie));
561 	return result;
562 }
563 
564 
565 // _user_find_disk_system
566 status_t
567 _user_find_disk_system(const char *_name, user_disk_system_info *_info)
568 {
569 	if (!_name || !_info)
570 		return B_BAD_VALUE;
571 	char name[B_DISK_SYSTEM_NAME_LENGTH];
572 	status_t error = ddm_strlcpy(name, _name, B_DISK_SYSTEM_NAME_LENGTH);
573 	if (error)
574 		return error;
575 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
576 	if (ManagerLocker locker = manager) {
577 		if (KDiskSystem *diskSystem = manager->FindDiskSystem(name)) {
578 			user_disk_system_info info;
579 			diskSystem->GetInfo(&info);
580 			user_memcpy(_info, &info, sizeof(info));
581 			return B_OK;
582 		}
583 	}
584 	return B_ENTRY_NOT_FOUND;
585 }
586 
587 
588 // _user_defragment_partition
589 status_t
590 _user_defragment_partition(partition_id partitionID, int32* _changeCounter)
591 {
592 	// copy parameters in
593 	int32 changeCounter;
594 
595 	status_t error;
596 	if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
597 		return error;
598 
599 	// get the partition
600 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
601 	KPartition* partition = manager->WriteLockPartition(partitionID);
602 	if (!partition)
603 		return B_ENTRY_NOT_FOUND;
604 
605 	PartitionRegistrar registrar1(partition, true);
606 	PartitionRegistrar registrar2(partition->Device(), true);
607 	DeviceWriteLocker locker(partition->Device(), true);
608 
609 	// check change counter
610 	if (changeCounter != partition->ChangeCounter())
611 		return B_BAD_VALUE;
612 
613 	// the partition must be initialized
614 	KDiskSystem* diskSystem = partition->DiskSystem();
615 	if (!diskSystem)
616 		return B_BAD_VALUE;
617 
618 	// mark the partition busy and unlock
619 	if (!partition->CheckAndMarkBusy(false))
620 		return B_BUSY;
621 	locker.Unlock();
622 
623 	// defragment
624 	error = diskSystem->Defragment(partition, DUMMY_JOB_ID);
625 
626 	// re-lock and unmark busy
627 	locker.Lock();
628 	partition->UnmarkBusy(false);
629 
630 	if (error != B_OK)
631 		return error;
632 
633 	// return change counter
634 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
635 			!= B_OK) {
636 		return error;
637 	}
638 
639 	return B_OK;
640 }
641 
642 
643 // _user_repair_partition
644 status_t
645 _user_repair_partition(partition_id partitionID, int32* _changeCounter,
646 	bool checkOnly)
647 {
648 	// copy parameters in
649 	int32 changeCounter;
650 
651 	status_t error;
652 	if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
653 		return error;
654 
655 	// get the partition
656 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
657 	KPartition* partition = manager->WriteLockPartition(partitionID);
658 	if (!partition)
659 		return B_ENTRY_NOT_FOUND;
660 
661 	PartitionRegistrar registrar1(partition, true);
662 	PartitionRegistrar registrar2(partition->Device(), true);
663 	DeviceWriteLocker locker(partition->Device(), true);
664 
665 	// check change counter
666 	if (changeCounter != partition->ChangeCounter())
667 		return B_BAD_VALUE;
668 
669 	// the partition must be initialized
670 	KDiskSystem* diskSystem = partition->DiskSystem();
671 	if (!diskSystem)
672 		return B_BAD_VALUE;
673 
674 	// mark the partition busy and unlock
675 	if (!partition->CheckAndMarkBusy(false))
676 		return B_BUSY;
677 	locker.Unlock();
678 
679 	// repair/check
680 	error = diskSystem->Repair(partition, checkOnly, DUMMY_JOB_ID);
681 
682 	// re-lock and unmark busy
683 	locker.Lock();
684 	partition->UnmarkBusy(false);
685 
686 	if (error != B_OK)
687 		return error;
688 
689 	// return change counter
690 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
691 			!= B_OK) {
692 		return error;
693 	}
694 
695 	return B_OK;
696 }
697 
698 
699 // _user_resize_partition
700 status_t
701 _user_resize_partition(partition_id partitionID, int32* _changeCounter,
702 	partition_id childID, int32* _childChangeCounter, off_t size,
703 	off_t contentSize)
704 {
705 	// copy parameters in
706 	int32 changeCounter;
707 	int32 childChangeCounter;
708 
709 	status_t error;
710 	if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK
711 		|| (error = copy_from_user_value(childChangeCounter,
712 			_childChangeCounter)) != B_OK) {
713 		return error;
714 	}
715 
716 	// get the partition
717 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
718 	KPartition* partition = manager->WriteLockPartition(partitionID);
719 	if (!partition)
720 		return B_ENTRY_NOT_FOUND;
721 
722 	PartitionRegistrar registrar1(partition, true);
723 	PartitionRegistrar registrar2(partition->Device(), true);
724 	DeviceWriteLocker locker(partition->Device(), true);
725 
726 	// register child
727 	KPartition* child = manager->RegisterPartition(childID);
728 	if (!child)
729 		return B_ENTRY_NOT_FOUND;
730 
731 	PartitionRegistrar registrar3(child, true);
732 
733 	// check change counters
734 	if (changeCounter != partition->ChangeCounter()
735 		|| childChangeCounter != child->ChangeCounter()) {
736 		return B_BAD_VALUE;
737 	}
738 
739 	// the partition must be initialized
740 	KDiskSystem* diskSystem = partition->DiskSystem();
741 	if (!diskSystem)
742 		return B_BAD_VALUE;
743 
744 	// child must indeed be a child of partition
745 	if (child->Parent() != partition)
746 		return B_BAD_VALUE;
747 
748 	// check sizes
749 	if (size < 0 || contentSize < 0 || size < contentSize
750 		|| size > partition->ContentSize()) {
751 		return B_BAD_VALUE;
752 	}
753 
754 	// mark the partitions busy and unlock
755 	if (partition->IsBusy() || child->IsBusy())
756 		return B_BUSY;
757 	partition->SetBusy(true);
758 	child->SetBusy(true);
759 	locker.Unlock();
760 
761 	// resize contents first, if shrinking
762 	if (child->DiskSystem() && contentSize < child->ContentSize())
763 		error = child->DiskSystem()->Resize(child, contentSize, DUMMY_JOB_ID);
764 
765 	// resize the partition
766 	if (error == B_OK && size != child->Size())
767 		error = diskSystem->ResizeChild(child, size, DUMMY_JOB_ID);
768 
769 	// resize contents last, if growing
770 	if (error == B_OK && child->DiskSystem()
771 		&& contentSize > child->ContentSize()) {
772 		error = child->DiskSystem()->Resize(child, contentSize, DUMMY_JOB_ID);
773 	}
774 
775 	// re-lock and unmark busy
776 	locker.Lock();
777 	partition->SetBusy(false);
778 	child->SetBusy(false);
779 
780 	if (error != B_OK)
781 		return error;
782 
783 	// return change counters
784 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
785 			!= B_OK
786 		|| (error = copy_to_user_value(_childChangeCounter,
787 			child->ChangeCounter())) != B_OK) {
788 		return error;
789 	}
790 
791 	return B_OK;
792 }
793 
794 
795 // _user_move_partition
796 status_t
797 _user_move_partition(partition_id partitionID, int32* changeCounter,
798 	partition_id childID, int32* childChangeCounter, off_t newOffset,
799 	partition_id* descendantIDs, int32* descendantChangeCounters,
800 	int32 descendantCount)
801 {
802 #if 0
803 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
804 	// get the partition
805 	KPartition *partition = manager->WriteLockPartition(partitionID);
806 	if (!partition)
807 		return B_ENTRY_NOT_FOUND;
808 	PartitionRegistrar registrar1(partition, true);
809 	PartitionRegistrar registrar2(partition->Device(), true);
810 	DeviceWriteLocker locker(partition->Device(), true);
811 	// check the new offset
812 	if (newOffset == partition->Offset())
813 		return B_OK;
814 	off_t proposedOffset = newOffset;
815 	status_t error = validate_move_partition(partition, changeCounter,
816 		&proposedOffset, true);
817 	if (error != B_OK)
818 		return error;
819 	if (proposedOffset != newOffset)
820 		return B_BAD_VALUE;
821 	// new offset is fine -- move the thing
822 	off_t moveBy = newOffset - partition->Offset();
823 	move_descendants(partition, moveBy);
824 	partition->Changed(B_PARTITION_CHANGED_OFFSET);
825 	// implicit partitioning system changes
826 	error = partition->Parent()->DiskSystem()->ShadowPartitionChanged(
827 		partition->Parent(), partition, B_PARTITION_MOVE_CHILD);
828 	if (error != B_OK)
829 		return error;
830 	// implicit descendants' content disk system changes
831 	return move_descendants_contents(partition);
832 #endif
833 return B_BAD_VALUE;
834 }
835 
836 
837 // _user_set_partition_name
838 status_t
839 _user_set_partition_name(partition_id partitionID, int32* _changeCounter,
840 	partition_id childID, int32* _childChangeCounter, const char* _name)
841 {
842 	// copy parameters in
843 	UserStringParameter<false> name;
844 	int32 changeCounter;
845 	int32 childChangeCounter;
846 
847 	status_t error;
848 	if ((error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
849 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
850 			!= B_OK
851 		|| (error = copy_from_user_value(childChangeCounter,
852 			_childChangeCounter)) != B_OK) {
853 		return error;
854 	}
855 
856 	// get the partition
857 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
858 	KPartition* partition = manager->WriteLockPartition(partitionID);
859 	if (!partition)
860 		return B_ENTRY_NOT_FOUND;
861 
862 	PartitionRegistrar registrar1(partition, true);
863 	PartitionRegistrar registrar2(partition->Device(), true);
864 	DeviceWriteLocker locker(partition->Device(), true);
865 
866 	// register child
867 	KPartition* child = manager->RegisterPartition(childID);
868 	if (!child)
869 		return B_ENTRY_NOT_FOUND;
870 
871 	PartitionRegistrar registrar3(child, true);
872 
873 	// check change counters
874 	if (changeCounter != partition->ChangeCounter()
875 		|| childChangeCounter != child->ChangeCounter()) {
876 		return B_BAD_VALUE;
877 	}
878 
879 	// the partition must be initialized
880 	KDiskSystem* diskSystem = partition->DiskSystem();
881 	if (!diskSystem)
882 		return B_BAD_VALUE;
883 
884 	// child must indeed be a child of partition
885 	if (child->Parent() != partition)
886 		return B_BAD_VALUE;
887 
888 	// mark the partitions busy and unlock
889 	if (partition->IsBusy() || child->IsBusy())
890 		return B_BUSY;
891 	partition->SetBusy(true);
892 	child->SetBusy(true);
893 	locker.Unlock();
894 
895 	// set the child name
896 	error = diskSystem->SetName(child, name.value, DUMMY_JOB_ID);
897 
898 	// re-lock and unmark busy
899 	locker.Lock();
900 	partition->SetBusy(false);
901 	child->SetBusy(false);
902 
903 	if (error != B_OK)
904 		return error;
905 
906 	// return change counters
907 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
908 			!= B_OK
909 		|| (error = copy_to_user_value(_childChangeCounter,
910 			child->ChangeCounter())) != B_OK) {
911 		return error;
912 	}
913 
914 	return B_OK;
915 }
916 
917 
918 // _user_set_partition_content_name
919 status_t
920 _user_set_partition_content_name(partition_id partitionID,
921 	int32* _changeCounter, const char* _name)
922 {
923 	// copy parameters in
924 	UserStringParameter<true> name;
925 	int32 changeCounter;
926 
927 	status_t error;
928 	if ((error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
929 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
930 			!= B_OK) {
931 		return error;
932 	}
933 
934 	// get the partition
935 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
936 	KPartition* partition = manager->WriteLockPartition(partitionID);
937 	if (!partition)
938 		return B_ENTRY_NOT_FOUND;
939 
940 	PartitionRegistrar registrar1(partition, true);
941 	PartitionRegistrar registrar2(partition->Device(), true);
942 	DeviceWriteLocker locker(partition->Device(), true);
943 
944 	// check change counter
945 	if (changeCounter != partition->ChangeCounter())
946 		return B_BAD_VALUE;
947 
948 	// the partition must be initialized
949 	KDiskSystem* diskSystem = partition->DiskSystem();
950 	if (!diskSystem)
951 		return B_BAD_VALUE;
952 
953 	// mark the partition busy and unlock
954 	if (!partition->CheckAndMarkBusy(false))
955 		return B_BUSY;
956 	locker.Unlock();
957 
958 	// set content parameters
959 	error = diskSystem->SetContentName(partition, name.value, DUMMY_JOB_ID);
960 
961 	// re-lock and unmark busy
962 	locker.Lock();
963 	partition->UnmarkBusy(false);
964 
965 	if (error != B_OK)
966 		return error;
967 
968 	// return change counter
969 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
970 			!= B_OK) {
971 		return error;
972 	}
973 
974 	return B_OK;
975 }
976 
977 
978 // _user_set_partition_type
979 status_t
980 _user_set_partition_type(partition_id partitionID, int32* _changeCounter,
981 	partition_id childID, int32* _childChangeCounter, const char* _type)
982 {
983 	// copy parameters in
984 	UserStringParameter<false> type;
985 	int32 changeCounter;
986 	int32 childChangeCounter;
987 
988 	status_t error;
989 	if ((error = type.Init(_type, B_DISK_DEVICE_TYPE_LENGTH)) != B_OK
990 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
991 			!= B_OK
992 		|| (error = copy_from_user_value(childChangeCounter,
993 			_childChangeCounter)) != B_OK) {
994 		return error;
995 	}
996 
997 	// get the partition
998 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
999 	KPartition* partition = manager->WriteLockPartition(partitionID);
1000 	if (!partition)
1001 		return B_ENTRY_NOT_FOUND;
1002 
1003 	PartitionRegistrar registrar1(partition, true);
1004 	PartitionRegistrar registrar2(partition->Device(), true);
1005 	DeviceWriteLocker locker(partition->Device(), true);
1006 
1007 	// register child
1008 	KPartition* child = manager->RegisterPartition(childID);
1009 	if (!child)
1010 		return B_ENTRY_NOT_FOUND;
1011 
1012 	PartitionRegistrar registrar3(child, true);
1013 
1014 	// check change counters
1015 	if (changeCounter != partition->ChangeCounter()
1016 		|| childChangeCounter != child->ChangeCounter()) {
1017 		return B_BAD_VALUE;
1018 	}
1019 
1020 	// the partition must be initialized
1021 	KDiskSystem* diskSystem = partition->DiskSystem();
1022 	if (!diskSystem)
1023 		return B_BAD_VALUE;
1024 
1025 	// child must indeed be a child of partition
1026 	if (child->Parent() != partition)
1027 		return B_BAD_VALUE;
1028 
1029 	// mark the partition busy and unlock
1030 	if (partition->IsBusy() || child->IsBusy())
1031 		return B_BUSY;
1032 	partition->SetBusy(true);
1033 	child->SetBusy(true);
1034 	locker.Unlock();
1035 
1036 	// set the child type
1037 	error = diskSystem->SetType(child, type.value, DUMMY_JOB_ID);
1038 
1039 	// re-lock and unmark busy
1040 	locker.Lock();
1041 	partition->SetBusy(false);
1042 	child->SetBusy(false);
1043 
1044 	if (error != B_OK)
1045 		return error;
1046 
1047 	// return change counters
1048 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1049 			!= B_OK
1050 		|| (error = copy_to_user_value(_childChangeCounter,
1051 			child->ChangeCounter())) != B_OK) {
1052 		return error;
1053 	}
1054 
1055 	return B_OK;
1056 }
1057 
1058 
1059 // _user_set_partition_parameters
1060 status_t
1061 _user_set_partition_parameters(partition_id partitionID, int32* _changeCounter,
1062 	partition_id childID, int32* _childChangeCounter, const char* _parameters,
1063 	size_t parametersSize)
1064 {
1065 	// copy parameters in
1066 	UserMemoryParameter<char, true> parameters;
1067 	int32 changeCounter;
1068 	int32 childChangeCounter;
1069 
1070 	status_t error;
1071 	if ((error = parameters.Init(_parameters, parametersSize,
1072 			B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK
1073 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
1074 			!= B_OK
1075 		|| (error = copy_from_user_value(childChangeCounter,
1076 			_childChangeCounter)) != B_OK) {
1077 		return error;
1078 	}
1079 
1080 	// get the partition
1081 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1082 	KPartition* partition = manager->WriteLockPartition(partitionID);
1083 	if (!partition)
1084 		return B_ENTRY_NOT_FOUND;
1085 
1086 	PartitionRegistrar registrar1(partition, true);
1087 	PartitionRegistrar registrar2(partition->Device(), true);
1088 	DeviceWriteLocker locker(partition->Device(), true);
1089 
1090 	// register child
1091 	KPartition* child = manager->RegisterPartition(childID);
1092 	if (!child)
1093 		return B_ENTRY_NOT_FOUND;
1094 
1095 	PartitionRegistrar registrar3(child, true);
1096 
1097 	// check change counters
1098 	if (changeCounter != partition->ChangeCounter()
1099 		|| childChangeCounter != child->ChangeCounter()) {
1100 		return B_BAD_VALUE;
1101 	}
1102 
1103 	// the partition must be initialized
1104 	KDiskSystem* diskSystem = partition->DiskSystem();
1105 	if (!diskSystem)
1106 		return B_BAD_VALUE;
1107 
1108 	// child must indeed be a child of partition
1109 	if (child->Parent() != partition)
1110 		return B_BAD_VALUE;
1111 
1112 	// mark the partition busy and unlock
1113 	if (partition->IsBusy() || child->IsBusy())
1114 		return B_BUSY;
1115 	partition->SetBusy(true);
1116 	child->SetBusy(true);
1117 	locker.Unlock();
1118 
1119 	// set the child parameters
1120 	error = diskSystem->SetParameters(child, parameters.value, DUMMY_JOB_ID);
1121 
1122 	// re-lock and unmark busy
1123 	locker.Lock();
1124 	partition->SetBusy(false);
1125 	child->SetBusy(false);
1126 
1127 	if (error != B_OK)
1128 		return error;
1129 
1130 	// return change counters
1131 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1132 			!= B_OK
1133 		|| (error = copy_to_user_value(_childChangeCounter,
1134 			child->ChangeCounter())) != B_OK) {
1135 		return error;
1136 	}
1137 
1138 	return B_OK;
1139 }
1140 
1141 
1142 // _user_set_partition_content_parameters
1143 status_t
1144 _user_set_partition_content_parameters(partition_id partitionID,
1145 	int32* _changeCounter, const char* _parameters, size_t parametersSize)
1146 {
1147 	// copy parameters in
1148 	UserMemoryParameter<char, true> parameters;
1149 	int32 changeCounter;
1150 
1151 	status_t error;
1152 	if ((error = parameters.Init(_parameters, parametersSize,
1153 			B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK
1154 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
1155 			!= B_OK) {
1156 		return error;
1157 	}
1158 
1159 	// get the partition
1160 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1161 	KPartition* partition = manager->WriteLockPartition(partitionID);
1162 	if (!partition)
1163 		return B_ENTRY_NOT_FOUND;
1164 
1165 	PartitionRegistrar registrar1(partition, true);
1166 	PartitionRegistrar registrar2(partition->Device(), true);
1167 	DeviceWriteLocker locker(partition->Device(), true);
1168 
1169 	// check change counter
1170 	if (changeCounter != partition->ChangeCounter())
1171 		return B_BAD_VALUE;
1172 
1173 	// the partition must be initialized
1174 	KDiskSystem* diskSystem = partition->DiskSystem();
1175 	if (!diskSystem)
1176 		return B_BAD_VALUE;
1177 
1178 	// mark the partition busy and unlock
1179 	if (!partition->CheckAndMarkBusy(true))
1180 		return B_BUSY;
1181 	locker.Unlock();
1182 
1183 	// set content parameters
1184 	error = diskSystem->SetContentParameters(partition, parameters.value,
1185 		DUMMY_JOB_ID);
1186 
1187 	// re-lock and unmark busy
1188 	locker.Lock();
1189 	partition->UnmarkBusy(true);
1190 
1191 	if (error != B_OK)
1192 		return error;
1193 
1194 	// return change counter
1195 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1196 			!= B_OK) {
1197 		return error;
1198 	}
1199 
1200 	return B_OK;
1201 }
1202 
1203 
1204 // _user_initialize_partition
1205 status_t
1206 _user_initialize_partition(partition_id partitionID, int32* _changeCounter,
1207 	const char* _diskSystemName, const char* _name, const char* _parameters,
1208 	size_t parametersSize)
1209 {
1210 	// copy parameters in
1211 	UserStringParameter<false> diskSystemName;
1212 	UserStringParameter<true> name;
1213 	UserMemoryParameter<char, true> parameters;
1214 	int32 changeCounter;
1215 
1216 	status_t error;
1217 	if ((error = diskSystemName.Init(_diskSystemName,
1218 			B_DISK_SYSTEM_NAME_LENGTH)) != B_OK
1219 		|| (error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
1220 		|| (error = parameters.Init(_parameters, parametersSize,
1221 			B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK
1222 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
1223 			!= B_OK) {
1224 		return error;
1225 	}
1226 
1227 	// get the partition
1228 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1229 	KPartition* partition = manager->WriteLockPartition(partitionID);
1230 	if (!partition)
1231 		return B_ENTRY_NOT_FOUND;
1232 
1233 	PartitionRegistrar registrar1(partition, true);
1234 	PartitionRegistrar registrar2(partition->Device(), true);
1235 	DeviceWriteLocker locker(partition->Device(), true);
1236 
1237 	// check change counter
1238 	if (changeCounter != partition->ChangeCounter())
1239 		return B_BAD_VALUE;
1240 
1241 	// the partition must be uninitialized
1242 	if (partition->DiskSystem())
1243 		return B_BAD_VALUE;
1244 
1245 	// load the new disk system
1246 	KDiskSystem *diskSystem = manager->LoadDiskSystem(diskSystemName.value,
1247 		true);
1248 	if (!diskSystem)
1249 		return B_ENTRY_NOT_FOUND;
1250 	DiskSystemLoader loader(diskSystem, true);
1251 
1252 	// mark the partition busy and unlock
1253 	if (!partition->CheckAndMarkBusy(true))
1254 		return B_BUSY;
1255 	locker.Unlock();
1256 
1257 	// let the disk system initialize the partition
1258 	error = diskSystem->Initialize(partition, name.value, parameters.value,
1259 		DUMMY_JOB_ID);
1260 
1261 	// re-lock and unmark busy
1262 	locker.Lock();
1263 	partition->UnmarkBusy(true);
1264 
1265 	if (error != B_OK)
1266 		return error;
1267 
1268 	partition->SetDiskSystem(diskSystem);
1269 
1270 	// return change counter
1271 	error = copy_to_user_value(_changeCounter, partition->ChangeCounter());
1272 	if (error != B_OK)
1273 		return error;
1274 
1275 	return B_OK;
1276 }
1277 
1278 
1279 // _user_uninitialize_partition
1280 status_t
1281 _user_uninitialize_partition(partition_id partitionID, int32* _changeCounter)
1282 {
1283 	// copy parameters in
1284 	int32 changeCounter;
1285 
1286 	status_t error;
1287 	if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
1288 		return error;
1289 
1290 	// get the partition
1291 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1292 	KPartition* partition = manager->WriteLockPartition(partitionID);
1293 	if (!partition)
1294 		return B_ENTRY_NOT_FOUND;
1295 
1296 	PartitionRegistrar registrar1(partition, true);
1297 	PartitionRegistrar registrar2(partition->Device(), true);
1298 	DeviceWriteLocker locker(partition->Device(), true);
1299 
1300 	// check change counter
1301 	if (changeCounter != partition->ChangeCounter())
1302 		return B_BAD_VALUE;
1303 
1304 	// the partition must be initialized
1305 	if (!partition->DiskSystem())
1306 		return B_BAD_VALUE;
1307 
1308 	// check busy
1309 	if (!partition->CheckAndMarkBusy(true))
1310 		return B_BUSY;
1311 
1312 // TODO: We should also check, if any partition is mounted!
1313 
1314 	// uninitialize
1315 	error = partition->UninitializeContents(true);
1316 
1317 	partition->UnmarkBusy(true);
1318 
1319 	if (error != B_OK)
1320 		return error;
1321 
1322 	// return change counter
1323 	error = copy_to_user_value(_changeCounter, partition->ChangeCounter());
1324 	if (error != B_OK)
1325 		return error;
1326 
1327 	return B_OK;
1328 }
1329 
1330 
1331 // _user_create_child_partition
1332 status_t
1333 _user_create_child_partition(partition_id partitionID, int32* _changeCounter,
1334 	off_t offset, off_t size, const char* _type, const char* _name,
1335 	const char* _parameters, size_t parametersSize, partition_id* childID,
1336 	int32* childChangeCounter)
1337 
1338 {
1339 	// copy parameters in
1340 	UserStringParameter<false> type;
1341 	UserStringParameter<true> name;
1342 	UserMemoryParameter<char, true> parameters;
1343 	int32 changeCounter;
1344 
1345 	status_t error;
1346 	if ((error = type.Init(_type, B_DISK_DEVICE_TYPE_LENGTH)) != B_OK
1347 		|| (error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
1348 		|| (error = parameters.Init(_parameters, parametersSize,
1349 			B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK
1350 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
1351 			!= B_OK) {
1352 		return error;
1353 	}
1354 
1355 	// get the partition
1356 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1357 	KPartition* partition = manager->WriteLockPartition(partitionID);
1358 	if (!partition)
1359 		return B_ENTRY_NOT_FOUND;
1360 
1361 	PartitionRegistrar registrar1(partition, true);
1362 	PartitionRegistrar registrar2(partition->Device(), true);
1363 	DeviceWriteLocker locker(partition->Device(), true);
1364 
1365 	// check change counter
1366 	if (changeCounter != partition->ChangeCounter())
1367 		return B_BAD_VALUE;
1368 
1369 	// the partition must be initialized
1370 	KDiskSystem* diskSystem = partition->DiskSystem();
1371 	if (!diskSystem)
1372 		return B_BAD_VALUE;
1373 
1374 	// mark the partition busy and unlock
1375 	if (!partition->CheckAndMarkBusy(false))
1376 		return B_BUSY;
1377 	locker.Unlock();
1378 
1379 	// create the child
1380 	KPartition *child = NULL;
1381 	error = diskSystem->CreateChild(partition, offset, size, type.value,
1382 		name.value, parameters.value, DUMMY_JOB_ID, &child, -1);
1383 
1384 	// re-lock and unmark busy
1385 	locker.Lock();
1386 	partition->UnmarkBusy(false);
1387 
1388 	if (error != B_OK)
1389 		return error;
1390 
1391 	if (child == NULL)
1392 		return B_ERROR;
1393 
1394 	child->UnmarkBusy(true);
1395 
1396 	// return change counter and child ID
1397 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1398 			!= B_OK
1399 		|| (error = copy_to_user_value(childID, child->ID())) != B_OK) {
1400 		return error;
1401 	}
1402 
1403 	return B_OK;
1404 }
1405 
1406 
1407 // _user_delete_child_partition
1408 status_t
1409 _user_delete_child_partition(partition_id partitionID, int32* _changeCounter,
1410 	partition_id childID, int32 childChangeCounter)
1411 {
1412 	// copy parameters in
1413 	int32 changeCounter;
1414 
1415 	status_t error;
1416 	if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
1417 		return error;
1418 
1419 	// get the partition
1420 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1421 	KPartition* partition = manager->WriteLockPartition(partitionID);
1422 	if (!partition)
1423 		return B_ENTRY_NOT_FOUND;
1424 
1425 	PartitionRegistrar registrar1(partition, true);
1426 	PartitionRegistrar registrar2(partition->Device(), true);
1427 	DeviceWriteLocker locker(partition->Device(), true);
1428 
1429 	// register child
1430 	KPartition* child = manager->RegisterPartition(childID);
1431 	if (!child)
1432 		return B_ENTRY_NOT_FOUND;
1433 
1434 	PartitionRegistrar registrar3(child, true);
1435 
1436 	// check change counters
1437 	if (changeCounter != partition->ChangeCounter()
1438 		|| childChangeCounter != child->ChangeCounter()) {
1439 		return B_BAD_VALUE;
1440 	}
1441 
1442 	// the partition must be initialized
1443 	KDiskSystem* diskSystem = partition->DiskSystem();
1444 	if (!diskSystem)
1445 		return B_BAD_VALUE;
1446 
1447 	// child must indeed be a child of partition
1448 	if (child->Parent() != partition)
1449 		return B_BAD_VALUE;
1450 
1451 	// mark the partition and child busy and unlock
1452 	if (partition->IsBusy() || !child->CheckAndMarkBusy(true))
1453 		return B_BUSY;
1454 	partition->SetBusy(true);
1455 	locker.Unlock();
1456 
1457 	// delete the child
1458 	error = diskSystem->DeleteChild(child, DUMMY_JOB_ID);
1459 
1460 	// re-lock and unmark busy
1461 	locker.Lock();
1462 	partition->SetBusy(false);
1463 	child->UnmarkBusy(true);
1464 
1465 	if (error != B_OK)
1466 		return error;
1467 
1468 	// return change counter
1469 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1470 			!= B_OK) {
1471 		return error;
1472 	}
1473 
1474 	return B_OK;
1475 }
1476