From a365e1cfbb80d7d2ee91e6515fa7090906cd5a4e Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 11 Jul 2009 14:35:04 +0000 Subject: [PATCH] Patch by Bryce Groff, some changes by myself: * devfs: - devfs_[un]publish_partition(): They no longer get the partition path as parameter, but rather the device path and the partition name. - Added devfs_rename_partition(), which renames an already published partition node. * KPartition/KDiskDevice: - Replaced the fPublished flag by fPublishedName, the name under which the partition is published. This simplifies UnpublishDevice() and makes it practically infallible. - Added GetFileName(), which only returns the partition's file name. Simplified GetPath() by using it. - When a partition is added/removed the subsequent sibling partitions get a new index. Now we also rename their published device nodes (and those of their descendents). When something goes wrong we unpublish the concerned partition's device to be on the safe side. Would be a shame to accidentally format the wrong partition, eh? :-) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31520 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/disk_device_manager/KDiskDevice.h | 2 + .../kernel/disk_device_manager/KPartition.h | 6 +- headers/private/kernel/fs/devfs.h | 6 +- src/system/kernel/device_manager/devfs.cpp | 116 +++++++++--- .../disk_device_manager/KDiskDevice.cpp | 34 +++- .../kernel/disk_device_manager/KPartition.cpp | 178 ++++++++++++------ 6 files changed, 245 insertions(+), 97 deletions(-) diff --git a/headers/private/kernel/disk_device_manager/KDiskDevice.h b/headers/private/kernel/disk_device_manager/KDiskDevice.h index fba729ef0f..ddb5cfcf3a 100644 --- a/headers/private/kernel/disk_device_manager/KDiskDevice.h +++ b/headers/private/kernel/disk_device_manager/KDiskDevice.h @@ -45,6 +45,7 @@ public: virtual status_t PublishDevice(); virtual status_t UnpublishDevice(); + virtual status_t RepublishDevice(); void SetDeviceFlags(uint32 flags); // comprises the ones below uint32 DeviceFlags() const; @@ -63,6 +64,7 @@ public: // TODO: Remove this method or make it private. Once initialized the // path must not be changed. const char *Path() const; + virtual status_t GetFileName(char* buffer, size_t size) const; virtual status_t GetPath(KPath *path) const; // File descriptor: Set only from a kernel thread, valid only for diff --git a/headers/private/kernel/disk_device_manager/KPartition.h b/headers/private/kernel/disk_device_manager/KPartition.h index e9a8cd8492..c831b6a6e0 100644 --- a/headers/private/kernel/disk_device_manager/KPartition.h +++ b/headers/private/kernel/disk_device_manager/KPartition.h @@ -48,6 +48,7 @@ public: virtual status_t Open(int flags, int *fd); virtual status_t PublishDevice(); virtual status_t UnpublishDevice(); + virtual status_t RepublishDevice(); bool IsPublished() const; void SetBusy(bool busy); @@ -106,6 +107,7 @@ public: virtual void SetID(partition_id id); partition_id ID() const; + virtual status_t GetFileName(char* buffer, size_t size) const; virtual status_t GetPath(KPath *path) const; // no setter (see BDiskDevice) -- built on the fly @@ -207,7 +209,7 @@ protected: void FireContentCookieChanged(void *cookie); private: - void _UpdateChildIndices(int32 index); + void _UpdateChildIndices(int32 start, int32 end); static int32 _NextID(); protected: @@ -226,7 +228,7 @@ protected: uint32 fAlgorithmData; int32 fReferenceCount; bool fObsolete; - bool fPublished; + char *fPublishedName; static int32 fNextID; }; diff --git a/headers/private/kernel/fs/devfs.h b/headers/private/kernel/fs/devfs.h index f5aad502d4..d53c7dc9c4 100644 --- a/headers/private/kernel/fs/devfs.h +++ b/headers/private/kernel/fs/devfs.h @@ -19,8 +19,10 @@ extern "C" { status_t devfs_unpublish_file_device(const char *path); status_t devfs_publish_file_device(const char *path, const char *filePath); -status_t devfs_unpublish_partition(const char *path); -status_t devfs_publish_partition(const char *path, const partition_info *info); +status_t devfs_unpublish_partition(const char *devicePath, const char *name); +status_t devfs_publish_partition(const char *name, const partition_info *info); +status_t devfs_rename_partition(const char *devicePath, const char *oldName, + const char *newName); status_t devfs_unpublish_device(const char *path, bool disconnect); status_t devfs_publish_device(const char *path, device_hooks *calls); diff --git a/src/system/kernel/device_manager/devfs.cpp b/src/system/kernel/device_manager/devfs.cpp index 7d121bece3..d7891f726e 100644 --- a/src/system/kernel/device_manager/devfs.cpp +++ b/src/system/kernel/device_manager/devfs.cpp @@ -321,7 +321,8 @@ devfs_find_in_dir(struct devfs_vnode* dir, const char* path) static status_t -devfs_insert_in_dir(struct devfs_vnode* dir, struct devfs_vnode* vnode) +devfs_insert_in_dir(struct devfs_vnode* dir, struct devfs_vnode* vnode, + bool notify = true) { if (!S_ISDIR(dir->stream.type)) return B_BAD_VALUE; @@ -347,17 +348,19 @@ devfs_insert_in_dir(struct devfs_vnode* dir, struct devfs_vnode* vnode) vnode->parent = dir; dir->modification_time = current_timespec(); - notify_entry_created(sDeviceFileSystem->id, dir->id, vnode->name, - vnode->id); - notify_stat_changed(sDeviceFileSystem->id, dir->id, - B_STAT_MODIFICATION_TIME); - + if (notify) { + notify_entry_created(sDeviceFileSystem->id, dir->id, vnode->name, + vnode->id); + notify_stat_changed(sDeviceFileSystem->id, dir->id, + B_STAT_MODIFICATION_TIME); + } return B_OK; } static status_t -devfs_remove_from_dir(struct devfs_vnode* dir, struct devfs_vnode* removeNode) +devfs_remove_from_dir(struct devfs_vnode* dir, struct devfs_vnode* removeNode, + bool notify = true) { struct devfs_vnode *vnode = dir->stream.u.dir.dir_head; struct devfs_vnode *lastNode = NULL; @@ -374,10 +377,12 @@ devfs_remove_from_dir(struct devfs_vnode* dir, struct devfs_vnode* removeNode) vnode->dir_next = NULL; dir->modification_time = current_timespec(); - notify_entry_removed(sDeviceFileSystem->id, dir->id, vnode->name, - vnode->id); - notify_stat_changed(sDeviceFileSystem->id, dir->id, - B_STAT_MODIFICATION_TIME); + if (notify) { + notify_entry_removed(sDeviceFileSystem->id, dir->id, vnode->name, + vnode->id); + notify_stat_changed(sDeviceFileSystem->id, dir->id, + B_STAT_MODIFICATION_TIME); + } return B_OK; } } @@ -2026,30 +2031,43 @@ devfs_publish_file_device(const char *path, const char *filePath) extern "C" status_t -devfs_unpublish_partition(const char *path) +devfs_unpublish_partition(const char *devicePath, const char *name) { - return unpublish_node(sDeviceFileSystem, path, S_IFCHR); + // get the device node + devfs_vnode* deviceNode; + status_t status = get_node_for_path(sDeviceFileSystem, devicePath, + &deviceNode); + if (status != B_OK) + return status; + + // get the partition node and temporarily increment its ref count + RecursiveLocker locker(sDeviceFileSystem->lock); + devfs_vnode* node = devfs_find_in_dir(deviceNode->parent, name); + if (node != NULL) + status = get_vnode(sDeviceFileSystem->volume, node->id, (void**)&node); + else + status = B_ENTRY_NOT_FOUND; + locker.Unlock(); + + // unpublish the partition node + if (status == B_OK) { + status = unpublish_node(sDeviceFileSystem, node, S_IFCHR); + put_vnode(sDeviceFileSystem->volume, node->id); + } + + put_vnode(sDeviceFileSystem->volume, deviceNode->id); + + return status; } extern "C" status_t -devfs_publish_partition(const char* path, const partition_info* info) +devfs_publish_partition(const char* name, const partition_info* info) { - if (path == NULL || info == NULL) + if (name == NULL || info == NULL) return B_BAD_VALUE; - TRACE(("publish partition: %s (device \"%s\", offset %Ld, size %Ld)\n", - path, info->device, info->offset, info->size)); - - // the partition and device paths must be the same until the leaves - const char* lastPath = strrchr(path, '/'); - const char* lastDevice = strrchr(info->device, '/'); - if (lastPath == NULL || lastDevice == NULL) - return B_BAD_VALUE; - - size_t length = lastDevice - (lastPath - path) - info->device; - if (strncmp(path, info->device + length, lastPath - path)) - return B_BAD_VALUE; + name, info->device, info->offset, info->size)); devfs_vnode* device; status_t status = get_node_for_path(sDeviceFileSystem, info->device, @@ -2057,13 +2075,55 @@ devfs_publish_partition(const char* path, const partition_info* info) if (status != B_OK) return status; - status = add_partition(sDeviceFileSystem, device, lastPath + 1, *info); + status = add_partition(sDeviceFileSystem, device, name, *info); put_vnode(sDeviceFileSystem->volume, device->id); return status; } +extern "C" status_t +devfs_rename_partition(const char *devicePath, const char* oldName, + const char *newName) +{ + status_t status; + devfs_vnode *device, *node; + if (oldName == NULL || newName == NULL) + return B_BAD_VALUE; + + status = get_node_for_path(sDeviceFileSystem, devicePath, &device); + if (status != B_OK) + return status; + + RecursiveLocker locker(sDeviceFileSystem->lock); + node = devfs_find_in_dir(device->parent, oldName); + if (node == NULL) + return B_ENTRY_NOT_FOUND; + + // check if the new path already exists + if (devfs_find_in_dir(device->parent, newName)) + return B_BAD_VALUE; + + char *name = strdup(newName); + if (name == NULL) + return B_NO_MEMORY; + + devfs_remove_from_dir(device->parent, node, false); + + free(node->name); + node->name = name; + + devfs_insert_in_dir(device->parent, node, false); + + notify_entry_moved(sDeviceFileSystem->id, device->parent->id, oldName, + device->parent->id, newName, node->id); + notify_stat_changed(sDeviceFileSystem->id, device->parent->id, + B_STAT_MODIFICATION_TIME); + + return B_OK; +} + + extern "C" status_t devfs_publish_directory(const char* path) { diff --git a/src/system/kernel/disk_device_manager/KDiskDevice.cpp b/src/system/kernel/disk_device_manager/KDiskDevice.cpp index 567feba020..3a99dc9bbf 100644 --- a/src/system/kernel/disk_device_manager/KDiskDevice.cpp +++ b/src/system/kernel/disk_device_manager/KDiskDevice.cpp @@ -1,4 +1,8 @@ -// KDiskDevice.cpp +/* + * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + #include #include @@ -29,7 +33,7 @@ KDiskDevice::KDiskDevice(partition_id id) { Unset(); fDevice = this; - fPublished = true; + fPublishedName = (char*)"raw"; } // destructor @@ -160,8 +164,8 @@ KDiskDevice::SetID(partition_id id) status_t KDiskDevice::PublishDevice() { - // PublishDevice() and UnpublishDevice() are no-ops for KDiskDevices, - // since they are always published. + // PublishDevice(), UnpublishDevice() and Republish are no-ops + // for KDiskDevices, since they are always published. return B_OK; } @@ -169,11 +173,19 @@ KDiskDevice::PublishDevice() status_t KDiskDevice::UnpublishDevice() { - // PublishDevice() and UnpublishDevice() are no-ops for KDiskDevices, - // since they are always published. + // PublishDevice(), UnpublishDevice() and Republish are no-ops + // for KDiskDevices, since they are always published. return B_OK; } +// RepublishDevice +status_t +KDiskDevice::RepublishDevice() +{ + // PublishDevice(), UnpublishDevice() and Republish are no-ops + // for KDiskDevices, since they are always published. + return B_OK; +} // SetDeviceFlags void @@ -269,6 +281,16 @@ KDiskDevice::Path() const return fDeviceData.path; } + +status_t +KDiskDevice::GetFileName(char *buffer, size_t size) const +{ + if (strlcpy(buffer, "raw", size) >= size) + return B_NAME_TOO_LONG; + return B_OK; +} + + // GetPath status_t KDiskDevice::GetPath(KPath *path) const diff --git a/src/system/kernel/disk_device_manager/KPartition.cpp b/src/system/kernel/disk_device_manager/KPartition.cpp index b05897db82..4b43a62201 100644 --- a/src/system/kernel/disk_device_manager/KPartition.cpp +++ b/src/system/kernel/disk_device_manager/KPartition.cpp @@ -1,6 +1,7 @@ /* + * Copyright 2009, Bryce Groff, bgroff@hawaii.edu. * Copyright 2004-2008, Haiku, Inc. All rights reserved. - * Copyright 2003-2004, Ingo Weinhold, bonefish@cs.tu-berlin.de. All rights reserved. + * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * * Distributed under the terms of the MIT License. */ @@ -57,7 +58,7 @@ KPartition::KPartition(partition_id id) fAlgorithmData(0), fReferenceCount(0), fObsolete(false), - fPublished(false) + fPublishedName(NULL) { fPartitionData.id = id >= 0 ? id : _NextID(); fPartitionData.offset = 0; @@ -179,17 +180,14 @@ KPartition::Open(int flags, int *fd) status_t KPartition::PublishDevice() { - if (fPublished) + if (fPublishedName) return B_OK; - // get the path - KPath path; - status_t error = GetPath(&path); - if (error != B_OK) { - dprintf("KPartition::PublishDevice(): Failed to get path for partition " - "%ld: %s\n", ID(), strerror(error)); + // get the name to publish + char buffer[B_FILE_NAME_LENGTH]; + status_t error = GetFileName(buffer, B_FILE_NAME_LENGTH); + if (error != B_OK) return error; - } // prepare a partition_info partition_info info; @@ -198,21 +196,24 @@ KPartition::PublishDevice() info.logical_block_size = BlockSize(); info.session = 0; info.partition = ID(); - if (strlcpy(info.device, Device()->Path(), B_PATH_NAME_LENGTH) - >= B_PATH_NAME_LENGTH) { + if (strlcpy(info.device, Device()->Path(), sizeof(info.device)) + >= sizeof(info.device)) { return B_NAME_TOO_LONG; } - error = devfs_publish_partition(path.Path() + 5, &info); - // we need to remove the "/dev/" part from the path + fPublishedName = strdup(buffer); + if (!fPublishedName) + return B_NO_MEMORY; + + error = devfs_publish_partition(buffer, &info); if (error != B_OK) { dprintf("KPartition::PublishDevice(): Failed to publish partition " "%ld: %s\n", ID(), strerror(error)); + free(fPublishedName); + fPublishedName = NULL; return error; } - fPublished = true; - return B_OK; } @@ -220,27 +221,63 @@ KPartition::PublishDevice() status_t KPartition::UnpublishDevice() { - if (!fPublished) + if (!fPublishedName) return B_OK; - // get the path - KPath path; - status_t error = GetPath(&path); + status_t error = devfs_unpublish_partition(Device()->Path(), + fPublishedName); if (error != B_OK) { - dprintf("KPartition::UnpublishDevice(): Failed to get path for " - "partition %ld: %s\n", ID(), strerror(error)); + dprintf("KPartition::UnpublishDevice(): Failed to unpublish partition " + "%ld: %s\n", ID(), strerror(error)); + } + + free(fPublishedName); + fPublishedName = NULL; + + return error; +} + + +// RepublishDevice +status_t +KPartition::RepublishDevice() +{ + if (!fPublishedName) + return B_OK; + + char newNameBuffer[B_FILE_NAME_LENGTH]; + status_t error = GetFileName(newNameBuffer, B_FILE_NAME_LENGTH); + if (error != B_OK) { + UnpublishDevice(); return error; } - fPublished = false; + if (strcmp(fPublishedName, newNameBuffer) == 0) + return B_OK; - error = devfs_unpublish_partition(path.Path() + 5); - // we need to remove the "/dev/" part from the path - if (error != B_OK) { - dprintf("KPartition::UnpublishDevice(): Failed to unpublish " - "partition %ld: %s\n", ID(), strerror(error)); + for (int i = 0; i < CountChildren(); i++) + ChildAt(i)->RepublishDevice(); + + char* newName = strdup(newNameBuffer); + if (!newName) { + UnpublishDevice(); + return B_NO_MEMORY; } - return error; + + error = devfs_rename_partition(Device()->Path(), fPublishedName, newName); + + if (error != B_OK) { + free(newName); + UnpublishDevice(); + dprintf("KPartition::RepublishDevice(): Failed to republish partition " + "%ld: %s\n", ID(), strerror(error)); + return error; + } + + free(fPublishedName); + fPublishedName = newName; + + return B_OK; } @@ -248,7 +285,7 @@ KPartition::UnpublishDevice() bool KPartition::IsPublished() const { - return fPublished; + return fPublishedName != NULL; } @@ -607,7 +644,30 @@ KPartition::ID() const return fPartitionData.id; } -// GetPath + +status_t +KPartition::GetFileName(char *buffer, size_t size) const +{ + // If the parent is the device, the name is the index of the partition. + if (Parent() == NULL || Parent()->IsDevice()) { + if (snprintf(buffer, size, "%ld", Index()) >= (int)size) + return B_NAME_TOO_LONG; + return B_OK; + } + + // The partition has a non-device parent, so we append the index to the + // parent partition's name. + status_t error = Parent()->GetFileName(buffer, size); + if (error != B_OK) + return error; + + size_t len = strlen(buffer); + if (snprintf(buffer + len, size - len, "_%ld", Index()) >= int(size - len)) + return B_NAME_TOO_LONG; + return B_OK; +} + + status_t KPartition::GetPath(KPath *path) const { @@ -615,34 +675,22 @@ KPartition::GetPath(KPath *path) const // Parent() is correct. if (!path || path->InitCheck() != B_OK || !Parent() || Index() < 0) return B_BAD_VALUE; - // get the parent's path - status_t error = Parent()->GetPath(path); + + // init the path with the device path + status_t error = path->SetPath(Device()->Path()); if (error != B_OK) return error; - if (Parent()->IsDevice()) { - // Our parent is a device, so we replace `raw' by our index. - const char *leaf = path->Leaf(); - if (!leaf || strcmp(leaf, "raw") != B_OK) - return B_ERROR; - #ifdef _KERNEL_MODE - char indexBuffer[12]; - snprintf(indexBuffer, sizeof(indexBuffer), "%ld", Index()); - #else - const char *prefix = "haiku_"; - char indexBuffer[strlen(prefix) + 12]; - snprintf(indexBuffer, sizeof(indexBuffer), "%s%ld", prefix, - Index()); - #endif - error = path->ReplaceLeaf(indexBuffer); - } else { - // Our parent is a normal partition, no device: Append our index. - char indexBuffer[13]; - snprintf(indexBuffer, sizeof(indexBuffer), "_%ld", Index()); - error = path->Append(indexBuffer, false); - } + + // replace the leaf name with the partition's file name + char name[B_FILE_NAME_LENGTH]; + error = GetFileName(name, sizeof(name)); + if (error == B_OK) + error = path->ReplaceLeaf(name); + return error; } + // SetVolumeID void KPartition::SetVolumeID(dev_t volumeID) @@ -780,9 +828,11 @@ KPartition::AddChild(KPartition *partition, int32 index) fChildren.Erase(index); return B_NO_MEMORY; } + // update siblings index's partition->SetIndex(index); - _UpdateChildIndices(index); + _UpdateChildIndices(count, index); fPartitionData.child_count++; + partition->SetParent(this); partition->SetDevice(Device()); @@ -843,7 +893,7 @@ KPartition::RemoveChild(int32 index) || !fChildren.Erase(index)) { return false; } - _UpdateChildIndices(index + 1); + _UpdateChildIndices(index, fChildren.Count()); partition->SetIndex(-1); fPartitionData.child_count--; partition->SetParent(NULL); @@ -1489,12 +1539,22 @@ KPartition::FireContentCookieChanged(void *cookie) // _UpdateChildIndices void -KPartition::_UpdateChildIndices(int32 index) +KPartition::_UpdateChildIndices(int32 start, int32 end) { - for (int32 i = index; i < fChildren.Count(); i++) - fChildren.ElementAt(i)->SetIndex(i); + if (start < end) { + for (int32 i = start; i < end; i++) { + fChildren.ElementAt(i)->SetIndex(i); + fChildren.ElementAt(i)->RepublishDevice(); + } + } else { + for (int32 i = start; i > end; i--) { + fChildren.ElementAt(i)->SetIndex(i); + fChildren.ElementAt(i)->RepublishDevice(); + } + } } + // _NextID int32 KPartition::_NextID()