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