2 * Copyright 2003-2017, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Ingo Weinhold, ingo_weinhold@gmx.de
7 * Axel Dörfler, axeld@pinc-software.de
10 /*! \file ddm_userland_interface.cpp
12 \brief Interface for userspace calls.
15 #include <ddm_userland_interface.h>
19 #include <AutoDeleter.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>
28 #include "UserDataWriter.h"
30 using namespace BPrivate::DiskDevice
;
36 // TODO: Replace all instances, when it has been decided how to handle
37 // notifications during jobs.
38 #define DUMMY_JOB_ID 0
41 // TODO: Add user address checks and check return values of user_memcpy()!
44 /*! \brief Wrapper around user_strlcpy() that returns a status_t
45 indicating appropriate success or failure.
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.
52 ddm_strlcpy(char *to
, const char *from
, size_t size
,
53 bool allowTruncation
= false)
55 ssize_t fromLen
= user_strlcpy(to
, from
, size
);
58 if ((size_t)fromLen
>= size
&& !allowTruncation
)
59 return B_NAME_TOO_LONG
;
64 template<typename Type
>
65 static inline status_t
66 copy_from_user_value(Type
& value
, const Type
* userValue
)
71 if (!IS_USER_ADDRESS(userValue
))
74 return user_memcpy(&value
, userValue
, sizeof(Type
));
78 template<typename Type
>
79 static inline status_t
80 copy_to_user_value(Type
* userValue
, const Type
& value
)
85 if (!IS_USER_ADDRESS(userValue
))
88 return user_memcpy(userValue
, &value
, sizeof(Type
));
92 template<bool kAllowsNull
>
93 struct UserStringParameter
{
96 inline UserStringParameter()
101 inline ~UserStringParameter()
106 inline status_t
Init(const char* userValue
, size_t maxSize
)
108 if (userValue
== NULL
) {
115 if (!IS_USER_ADDRESS(userValue
))
116 return B_BAD_ADDRESS
;
118 value
= (char*)malloc(maxSize
);
122 ssize_t bytesCopied
= user_strlcpy(value
, userValue
, maxSize
);
126 if ((size_t)bytesCopied
>= maxSize
)
127 return B_BUFFER_OVERFLOW
;
132 inline operator const char*()
137 inline operator char*()
146 move_descendants(KPartition
*partition
, off_t moveBy
)
150 partition
->SetOffset(partition
->Offset() + moveBy
);
152 for (int32 i
= 0; KPartition
*child
= partition
->ChildAt(i
); i
++)
153 move_descendants(child
, moveBy
);
158 move_descendants_contents(KPartition
*partition
)
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
);
170 // move children's contents
171 for (int32 i
= 0; KPartition
*child
= partition
->ChildAt(i
); i
++) {
172 status_t error
= move_descendants_contents(child
);
182 _user_get_next_disk_device_id(int32
*_cookie
, size_t *neededSize
)
187 user_memcpy(&cookie
, _cookie
, sizeof(cookie
));
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);
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());
209 user_memcpy(_cookie
, &cookie
, sizeof(cookie
));
215 _user_find_disk_device(const char *_filename
, size_t *neededSize
)
217 UserStringParameter
<false> filename
;
218 status_t error
= filename
.Init(_filename
, B_PATH_NAME_LENGTH
);
222 partition_id id
= B_ENTRY_NOT_FOUND
;
223 KDiskDeviceManager
*manager
= KDiskDeviceManager::Default();
225 if (KDiskDevice
*device
= manager
->RegisterDevice(filename
)) {
226 PartitionRegistrar
_(device
, true);
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());
245 _user_find_partition(const char *_filename
, size_t *neededSize
)
247 UserStringParameter
<false> filename
;
248 status_t error
= filename
.Init(_filename
, B_PATH_NAME_LENGTH
);
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();
259 // get and lock the partition's device
260 KDiskDevice
*device
= manager
->RegisterDevice(partition
->ID(),
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());
281 _user_find_file_disk_device(const char *_filename
, size_t *neededSize
)
283 UserStringParameter
<false> filename
;
284 status_t error
= filename
.Init(_filename
, B_PATH_NAME_LENGTH
);
288 KPath
path(filename
, KPath::NORMALIZE
);
290 partition_id id
= B_ENTRY_NOT_FOUND
;
291 KDiskDeviceManager
*manager
= KDiskDeviceManager::Default();
293 if (KFileDiskDevice
* device
= manager
->RegisterFileDevice(path
.Path())) {
294 PartitionRegistrar
_(device
, true);
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());
312 /*! \brief Writes data describing the disk device identified by ID and all
313 its partitions into the supplied buffer.
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).
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.
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.
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.
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
347 - \c B_ERROR: An unexpected error occured.
348 - another error code...
351 _user_get_disk_device_data(partition_id id
, bool deviceOnly
,
352 user_disk_device_data
*buffer
, size_t bufferSize
, size_t *_neededSize
)
354 if (!buffer
&& bufferSize
> 0)
356 KDiskDeviceManager
*manager
= KDiskDeviceManager::Default();
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();
366 status_t error
= copy_ref_var_to_user(neededSize
, _neededSize
);
370 // if no buffer has been supplied or the buffer is too small,
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
));
379 MemoryDeleter
deleter(kernelBuffer
);
380 // write the device data into the buffer
381 writer
.SetTo(kernelBuffer
, bufferSize
);
382 device
->WriteUserData(writer
);
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"));
390 status_t error
= writer
.Relocate(buffer
);
395 return user_memcpy(buffer
, kernelBuffer
, neededSize
);
399 return B_ENTRY_NOT_FOUND
;
404 _user_register_file_device(const char *_filename
)
406 UserStringParameter
<false> filename
;
407 status_t error
= filename
.Init(_filename
, B_PATH_NAME_LENGTH
);
411 KPath
path(filename
, KPath::NORMALIZE
);
413 KDiskDeviceManager
*manager
= KDiskDeviceManager::Default();
414 if (ManagerLocker locker
= manager
) {
415 if (KFileDiskDevice
*device
= manager
->FindFileDevice(path
.Path()))
417 return manager
->CreateFileDevice(path
.Path());
424 _user_unregister_file_device(partition_id deviceID
, const char *_filename
)
426 if (deviceID
< 0 && !_filename
)
428 KDiskDeviceManager
*manager
= KDiskDeviceManager::Default();
430 return manager
->DeleteFileDevice(deviceID
);
432 UserStringParameter
<false> filename
;
433 status_t error
= filename
.Init(_filename
, B_PATH_NAME_LENGTH
);
437 return manager
->DeleteFileDevice(filename
);
443 _user_get_file_disk_device_path(partition_id id
, char* buffer
,
446 if (id
< 0 || buffer
== NULL
|| bufferSize
== 0)
449 KDiskDeviceManager
*manager
= KDiskDeviceManager::Default();
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
)
459 ssize_t copied
= user_strlcpy(buffer
, fileDevice
->FilePath(),
463 return (size_t)copied
< bufferSize
? B_OK
: B_BUFFER_OVERFLOW
;
472 _user_get_disk_system_info(disk_system_id id
, user_disk_system_info
*_info
)
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
));
485 return B_ENTRY_NOT_FOUND
;
490 _user_get_next_disk_system_info(int32
*_cookie
, user_disk_system_info
*_info
)
492 if (!_cookie
|| !_info
)
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
));
506 user_memcpy(_cookie
, &cookie
, sizeof(cookie
));
512 _user_find_disk_system(const char *_name
, user_disk_system_info
*_info
)
514 if (!_name
|| !_info
)
516 char name
[B_DISK_SYSTEM_NAME_LENGTH
];
517 status_t error
= ddm_strlcpy(name
, _name
, B_DISK_SYSTEM_NAME_LENGTH
);
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
));
529 return B_ENTRY_NOT_FOUND
;
534 _user_defragment_partition(partition_id partitionID
, int32
* _changeCounter
)
536 // copy parameters in
540 if ((error
= copy_from_user_value(changeCounter
, _changeCounter
)) != B_OK
)
544 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
545 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
547 return B_ENTRY_NOT_FOUND
;
549 PartitionRegistrar
registrar1(partition
, true);
550 PartitionRegistrar
registrar2(partition
->Device(), true);
551 DeviceWriteLocker
locker(partition
->Device(), true);
553 // check change counter
554 if (changeCounter
!= partition
->ChangeCounter())
557 // the partition must be initialized
558 KDiskSystem
* diskSystem
= partition
->DiskSystem();
562 // mark the partition busy and unlock
563 if (!partition
->CheckAndMarkBusy(false))
568 error
= diskSystem
->Defragment(partition
, DUMMY_JOB_ID
);
570 // re-lock and unmark busy
572 partition
->UnmarkBusy(false);
577 // return change counter
578 if ((error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter()))
588 _user_repair_partition(partition_id partitionID
, int32
* _changeCounter
,
591 // copy parameters in
595 if ((error
= copy_from_user_value(changeCounter
, _changeCounter
)) != B_OK
)
599 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
600 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
602 return B_ENTRY_NOT_FOUND
;
604 PartitionRegistrar
registrar1(partition
, true);
605 PartitionRegistrar
registrar2(partition
->Device(), true);
606 DeviceWriteLocker
locker(partition
->Device(), true);
608 // check change counter
609 if (changeCounter
!= partition
->ChangeCounter())
612 // the partition must be initialized
613 KDiskSystem
* diskSystem
= partition
->DiskSystem();
617 // mark the partition busy and unlock
618 if (!partition
->CheckAndMarkBusy(false))
623 error
= diskSystem
->Repair(partition
, checkOnly
, DUMMY_JOB_ID
);
625 // re-lock and unmark busy
627 partition
->UnmarkBusy(false);
632 // return change counter
633 if ((error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter()))
643 _user_resize_partition(partition_id partitionID
, int32
* _changeCounter
,
644 partition_id childID
, int32
* _childChangeCounter
, off_t size
,
647 // copy parameters in
649 int32 childChangeCounter
;
652 if ((error
= copy_from_user_value(changeCounter
, _changeCounter
)) != B_OK
653 || (error
= copy_from_user_value(childChangeCounter
,
654 _childChangeCounter
)) != B_OK
) {
659 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
660 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
662 return B_ENTRY_NOT_FOUND
;
664 PartitionRegistrar
registrar1(partition
, true);
665 PartitionRegistrar
registrar2(partition
->Device(), true);
666 DeviceWriteLocker
locker(partition
->Device(), true);
669 KPartition
* child
= manager
->RegisterPartition(childID
);
671 return B_ENTRY_NOT_FOUND
;
673 PartitionRegistrar
registrar3(child
, true);
675 // check change counters
676 if (changeCounter
!= partition
->ChangeCounter()
677 || childChangeCounter
!= child
->ChangeCounter()) {
681 // the partition must be initialized
682 KDiskSystem
* diskSystem
= partition
->DiskSystem();
686 // child must indeed be a child of partition
687 if (child
->Parent() != partition
)
691 if (size
< 0 || contentSize
< 0 || size
< contentSize
692 || size
> partition
->ContentSize()) {
696 // mark the partitions busy and unlock
697 if (partition
->IsBusy() || child
->IsBusy())
699 partition
->SetBusy(true);
700 child
->SetBusy(true);
703 // resize contents first, if shrinking
704 if (child
->DiskSystem() && contentSize
< child
->ContentSize())
705 error
= child
->DiskSystem()->Resize(child
, contentSize
, DUMMY_JOB_ID
);
707 // resize the partition
708 if (error
== B_OK
&& size
!= child
->Size())
709 error
= diskSystem
->ResizeChild(child
, size
, DUMMY_JOB_ID
);
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
);
717 // re-lock and unmark busy
719 partition
->SetBusy(false);
720 child
->SetBusy(false);
725 // return change counters
726 if ((error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter()))
728 || (error
= copy_to_user_value(_childChangeCounter
,
729 child
->ChangeCounter())) != B_OK
) {
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
)
744 KDiskDeviceManager
*manager
= KDiskDeviceManager::Default();
746 KPartition
*partition
= manager
->WriteLockPartition(partitionID
);
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())
755 off_t proposedOffset
= newOffset
;
756 status_t error
= validate_move_partition(partition
, changeCounter
,
757 &proposedOffset
, true);
760 if (proposedOffset
!= newOffset
)
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
);
771 // implicit descendants' content disk system changes
772 return move_descendants_contents(partition
);
779 _user_set_partition_name(partition_id partitionID
, int32
* _changeCounter
,
780 partition_id childID
, int32
* _childChangeCounter
, const char* _name
)
782 // copy parameters in
783 UserStringParameter
<false> name
;
785 int32 childChangeCounter
;
788 if ((error
= name
.Init(_name
, B_DISK_DEVICE_NAME_LENGTH
)) != B_OK
789 || (error
= copy_from_user_value(changeCounter
, _changeCounter
))
791 || (error
= copy_from_user_value(childChangeCounter
,
792 _childChangeCounter
)) != B_OK
) {
797 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
798 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
800 return B_ENTRY_NOT_FOUND
;
802 PartitionRegistrar
registrar1(partition
, true);
803 PartitionRegistrar
registrar2(partition
->Device(), true);
804 DeviceWriteLocker
locker(partition
->Device(), true);
807 KPartition
* child
= manager
->RegisterPartition(childID
);
809 return B_ENTRY_NOT_FOUND
;
811 PartitionRegistrar
registrar3(child
, true);
813 // check change counters
814 if (changeCounter
!= partition
->ChangeCounter()
815 || childChangeCounter
!= child
->ChangeCounter()) {
819 // the partition must be initialized
820 KDiskSystem
* diskSystem
= partition
->DiskSystem();
824 // child must indeed be a child of partition
825 if (child
->Parent() != partition
)
828 // mark the partitions busy and unlock
829 if (partition
->IsBusy() || child
->IsBusy())
831 partition
->SetBusy(true);
832 child
->SetBusy(true);
835 // set the child name
836 error
= diskSystem
->SetName(child
, name
.value
, DUMMY_JOB_ID
);
838 // re-lock and unmark busy
840 partition
->SetBusy(false);
841 child
->SetBusy(false);
846 // return change counters
847 if ((error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter()))
849 || (error
= copy_to_user_value(_childChangeCounter
,
850 child
->ChangeCounter())) != B_OK
) {
859 _user_set_partition_content_name(partition_id partitionID
,
860 int32
* _changeCounter
, const char* _name
)
862 // copy parameters in
863 UserStringParameter
<true> name
;
867 if ((error
= name
.Init(_name
, B_DISK_DEVICE_NAME_LENGTH
)) != B_OK
868 || (error
= copy_from_user_value(changeCounter
, _changeCounter
))
874 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
875 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
877 return B_ENTRY_NOT_FOUND
;
879 PartitionRegistrar
registrar1(partition
, true);
880 PartitionRegistrar
registrar2(partition
->Device(), true);
881 DeviceWriteLocker
locker(partition
->Device(), true);
883 // check change counter
884 if (changeCounter
!= partition
->ChangeCounter())
887 // the partition must be initialized
888 KDiskSystem
* diskSystem
= partition
->DiskSystem();
892 // mark the partition busy and unlock
893 if (!partition
->CheckAndMarkBusy(false))
897 // set content parameters
898 error
= diskSystem
->SetContentName(partition
, name
.value
, DUMMY_JOB_ID
);
900 // re-lock and unmark busy
902 partition
->UnmarkBusy(false);
907 // return change counter
908 if ((error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter()))
918 _user_set_partition_type(partition_id partitionID
, int32
* _changeCounter
,
919 partition_id childID
, int32
* _childChangeCounter
, const char* _type
)
921 // copy parameters in
922 UserStringParameter
<false> type
;
924 int32 childChangeCounter
;
927 if ((error
= type
.Init(_type
, B_DISK_DEVICE_TYPE_LENGTH
)) != B_OK
928 || (error
= copy_from_user_value(changeCounter
, _changeCounter
))
930 || (error
= copy_from_user_value(childChangeCounter
,
931 _childChangeCounter
)) != B_OK
) {
936 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
937 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
939 return B_ENTRY_NOT_FOUND
;
941 PartitionRegistrar
registrar1(partition
, true);
942 PartitionRegistrar
registrar2(partition
->Device(), true);
943 DeviceWriteLocker
locker(partition
->Device(), true);
946 KPartition
* child
= manager
->RegisterPartition(childID
);
948 return B_ENTRY_NOT_FOUND
;
950 PartitionRegistrar
registrar3(child
, true);
952 // check change counters
953 if (changeCounter
!= partition
->ChangeCounter()
954 || childChangeCounter
!= child
->ChangeCounter()) {
958 // the partition must be initialized
959 KDiskSystem
* diskSystem
= partition
->DiskSystem();
963 // child must indeed be a child of partition
964 if (child
->Parent() != partition
)
967 // mark the partition busy and unlock
968 if (partition
->IsBusy() || child
->IsBusy())
970 partition
->SetBusy(true);
971 child
->SetBusy(true);
974 // set the child type
975 error
= diskSystem
->SetType(child
, type
.value
, DUMMY_JOB_ID
);
977 // re-lock and unmark busy
979 partition
->SetBusy(false);
980 child
->SetBusy(false);
985 // return change counters
986 if ((error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter()))
988 || (error
= copy_to_user_value(_childChangeCounter
,
989 child
->ChangeCounter())) != B_OK
) {
998 _user_set_partition_parameters(partition_id partitionID
, int32
* _changeCounter
,
999 partition_id childID
, int32
* _childChangeCounter
, const char* _parameters
)
1001 // copy parameters in
1002 UserStringParameter
<true> parameters
;
1003 int32 changeCounter
;
1004 int32 childChangeCounter
;
1007 if ((error
= parameters
.Init(_parameters
, B_DISK_DEVICE_MAX_PARAMETER_SIZE
))
1009 || (error
= copy_from_user_value(changeCounter
, _changeCounter
))
1011 || (error
= copy_from_user_value(childChangeCounter
,
1012 _childChangeCounter
)) != B_OK
) {
1016 // get the partition
1017 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
1018 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
1020 return B_ENTRY_NOT_FOUND
;
1022 PartitionRegistrar
registrar1(partition
, true);
1023 PartitionRegistrar
registrar2(partition
->Device(), true);
1024 DeviceWriteLocker
locker(partition
->Device(), true);
1027 KPartition
* child
= manager
->RegisterPartition(childID
);
1029 return B_ENTRY_NOT_FOUND
;
1031 PartitionRegistrar
registrar3(child
, true);
1033 // check change counters
1034 if (changeCounter
!= partition
->ChangeCounter()
1035 || childChangeCounter
!= child
->ChangeCounter()) {
1039 // the partition must be initialized
1040 KDiskSystem
* diskSystem
= partition
->DiskSystem();
1044 // child must indeed be a child of partition
1045 if (child
->Parent() != partition
)
1048 // mark the partition busy and unlock
1049 if (partition
->IsBusy() || child
->IsBusy())
1051 partition
->SetBusy(true);
1052 child
->SetBusy(true);
1055 // set the child parameters
1056 error
= diskSystem
->SetParameters(child
, parameters
.value
, DUMMY_JOB_ID
);
1058 // re-lock and unmark busy
1060 partition
->SetBusy(false);
1061 child
->SetBusy(false);
1066 // return change counters
1067 if ((error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter()))
1069 || (error
= copy_to_user_value(_childChangeCounter
,
1070 child
->ChangeCounter())) != B_OK
) {
1079 _user_set_partition_content_parameters(partition_id partitionID
,
1080 int32
* _changeCounter
, const char* _parameters
)
1082 // copy parameters in
1083 UserStringParameter
<true> parameters
;
1084 int32 changeCounter
;
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
) {
1093 // get the partition
1094 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
1095 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
1097 return B_ENTRY_NOT_FOUND
;
1099 PartitionRegistrar
registrar1(partition
, true);
1100 PartitionRegistrar
registrar2(partition
->Device(), true);
1101 DeviceWriteLocker
locker(partition
->Device(), true);
1103 // check change counter
1104 if (changeCounter
!= partition
->ChangeCounter())
1107 // the partition must be initialized
1108 KDiskSystem
* diskSystem
= partition
->DiskSystem();
1112 // mark the partition busy and unlock
1113 if (!partition
->CheckAndMarkBusy(true))
1117 // set content parameters
1118 error
= diskSystem
->SetContentParameters(partition
, parameters
.value
,
1121 // re-lock and unmark busy
1123 partition
->UnmarkBusy(true);
1128 // return change counter
1129 if ((error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter()))
1139 _user_initialize_partition(partition_id partitionID
, int32
* _changeCounter
,
1140 const char* _diskSystemName
, const char* _name
, const char* _parameters
)
1142 // copy parameters in
1143 UserStringParameter
<false> diskSystemName
;
1144 UserStringParameter
<true> name
;
1145 UserStringParameter
<true> parameters
;
1146 int32 changeCounter
;
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
))
1159 // get the partition
1160 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
1161 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
1163 return B_ENTRY_NOT_FOUND
;
1165 PartitionRegistrar
registrar1(partition
, true);
1166 PartitionRegistrar
registrar2(partition
->Device(), true);
1167 DeviceWriteLocker
locker(partition
->Device(), true);
1169 // check change counter
1170 if (changeCounter
!= partition
->ChangeCounter())
1173 // the partition must be uninitialized
1174 if (partition
->DiskSystem())
1177 // load the new disk system
1178 KDiskSystem
*diskSystem
= manager
->LoadDiskSystem(diskSystemName
.value
,
1181 return B_ENTRY_NOT_FOUND
;
1182 DiskSystemLoader
loader(diskSystem
, true);
1184 // mark the partition busy and unlock
1185 if (!partition
->CheckAndMarkBusy(true))
1189 // let the disk system initialize the partition
1190 error
= diskSystem
->Initialize(partition
, name
.value
, parameters
.value
,
1193 // re-lock and unmark busy
1195 partition
->UnmarkBusy(true);
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
);
1211 // return change counter
1212 error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter());
1221 _user_uninitialize_partition(partition_id partitionID
, int32
* _changeCounter
,
1222 partition_id parentID
, int32
* _parentChangeCounter
)
1224 // copy parameters in
1225 int32 changeCounter
;
1226 int32 parentChangeCounter
;
1227 bool haveParent
= parentID
>= 0;
1230 if ((error
= copy_from_user_value(changeCounter
, _changeCounter
)) != B_OK
)
1232 if (haveParent
&& (error
= copy_from_user_value(parentChangeCounter
,
1233 _parentChangeCounter
)) != B_OK
)
1236 // get the partition
1237 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
1238 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
1240 return B_ENTRY_NOT_FOUND
;
1242 PartitionRegistrar
registrar1(partition
, true);
1243 PartitionRegistrar
registrar2(partition
->Device(), true);
1244 DeviceWriteLocker
locker(partition
->Device(), true);
1247 KPartition
* parent
= NULL
;
1249 parent
= manager
->RegisterPartition(parentID
);
1251 PartitionRegistrar
registrar3(parent
, true);
1253 // check change counter
1254 if (changeCounter
!= partition
->ChangeCounter())
1256 if (haveParent
&& parentChangeCounter
!= parent
->ChangeCounter())
1259 // the partition must be initialized
1260 if (!partition
->DiskSystem())
1264 if (!partition
->CheckAndMarkBusy(true))
1267 if (partition
->IsMounted() || partition
->IsChildMounted())
1270 KDiskSystem
* diskSystem
= partition
->DiskSystem();
1274 // Let the disk system uninitialize the partition. This operation is not
1275 // mandatory. If implemented, it will destroy the on-disk structures, so
1276 // that the disk system cannot accidentally identify the partition later on.
1277 if (diskSystem
!= NULL
)
1278 diskSystem
->Uninitialize(partition
, DUMMY_JOB_ID
);
1280 // re-lock and uninitialize the partition object
1282 error
= partition
->UninitializeContents(true);
1284 partition
->UnmarkBusy(true);
1289 // return change counter
1290 error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter());
1293 if (haveParent
&& (error
= copy_to_user_value(_parentChangeCounter
,
1294 parent
->ChangeCounter())) != B_OK
)
1302 _user_create_child_partition(partition_id partitionID
, int32
* _changeCounter
,
1303 off_t offset
, off_t size
, const char* _type
, const char* _name
,
1304 const char* _parameters
, partition_id
* childID
, int32
* childChangeCounter
)
1306 // copy parameters in
1307 UserStringParameter
<false> type
;
1308 UserStringParameter
<true> name
;
1309 UserStringParameter
<true> parameters
;
1310 int32 changeCounter
;
1313 if ((error
= type
.Init(_type
, B_DISK_DEVICE_TYPE_LENGTH
)) != B_OK
1314 || (error
= name
.Init(_name
, B_DISK_DEVICE_NAME_LENGTH
)) != B_OK
1315 || (error
= parameters
.Init(_parameters
,
1316 B_DISK_DEVICE_MAX_PARAMETER_SIZE
)) != B_OK
1317 || (error
= copy_from_user_value(changeCounter
, _changeCounter
))
1322 // get the partition
1323 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
1324 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
1326 return B_ENTRY_NOT_FOUND
;
1328 PartitionRegistrar
registrar1(partition
, true);
1329 PartitionRegistrar
registrar2(partition
->Device(), true);
1330 DeviceWriteLocker
locker(partition
->Device(), true);
1332 // check change counter
1333 if (changeCounter
!= partition
->ChangeCounter())
1336 // the partition must be initialized
1337 KDiskSystem
* diskSystem
= partition
->DiskSystem();
1341 // mark the partition busy and unlock
1342 if (!partition
->CheckAndMarkBusy(false))
1347 KPartition
*child
= NULL
;
1348 error
= diskSystem
->CreateChild(partition
, offset
, size
, type
.value
,
1349 name
.value
, parameters
.value
, DUMMY_JOB_ID
, &child
, -1);
1351 // re-lock and unmark busy
1353 partition
->UnmarkBusy(false);
1361 child
->UnmarkBusy(true);
1363 // return change counter and child ID
1364 if ((error
= copy_to_user_value(_changeCounter
, partition
->ChangeCounter()))
1366 || (error
= copy_to_user_value(childID
, child
->ID())) != B_OK
) {
1375 _user_delete_child_partition(partition_id partitionID
, int32
* _changeCounter
,
1376 partition_id childID
, int32 childChangeCounter
)
1378 // copy parameters in
1379 int32 changeCounter
;
1382 if ((error
= copy_from_user_value(changeCounter
, _changeCounter
)) != B_OK
)
1385 // get the partition
1386 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
1387 KPartition
* partition
= manager
->WriteLockPartition(partitionID
);
1389 return B_ENTRY_NOT_FOUND
;
1391 PartitionRegistrar
registrar1(partition
, true);
1392 PartitionRegistrar
registrar2(partition
->Device(), true);
1393 DeviceWriteLocker
locker(partition
->Device(), true);
1396 KPartition
* child
= manager
->RegisterPartition(childID
);
1398 return B_ENTRY_NOT_FOUND
;
1400 PartitionRegistrar
registrar3(child
, true);
1402 // check change counters
1403 if (changeCounter
!= partition
->ChangeCounter()
1404 || childChangeCounter
!= child
->ChangeCounter()) {
1408 // the partition must be initialized
1409 KDiskSystem
* diskSystem
= partition
->DiskSystem();
1413 // child must indeed be a child of partition
1414 if (child
->Parent() != partition
)
1417 // mark the partition and child busy and unlock
1418 if (partition
->IsBusy() || !child
->CheckAndMarkBusy(true))
1420 partition
->SetBusy(true);
1424 error
= diskSystem
->DeleteChild(child
, DUMMY_JOB_ID
);
1426 // re-lock and unmark busy
1428 partition
->SetBusy(false);
1429 child
->UnmarkBusy(true);
1434 // return change counter
1435 return copy_to_user_value(_changeCounter
, partition
->ChangeCounter());
1440 _user_start_watching_disks(uint32 eventMask
, port_id port
, int32 token
)
1442 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
1443 return manager
->Notifications().UpdateUserListener(eventMask
, port
, token
);
1448 _user_stop_watching_disks(port_id port
, int32 token
)
1450 KDiskDeviceManager
* manager
= KDiskDeviceManager::Default();
1451 return manager
->Notifications().RemoveUserListeners(port
, token
);