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