* BFS now always writes back the whole block when it writes the super block.

* Therefore, I've added an I/O control that let's it update the boot block
  part of this block, so that makebootable can use it on a mounted volume
  (this will probably be moved into a disk system API later).
* Added user_memcpy() to the fs_shell.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23082 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-12-08 14:23:35 +00:00
parent 477d25de35
commit 21885de266
7 changed files with 71 additions and 48 deletions

View File

@ -932,9 +932,11 @@
// #pragma mark - fssh_kernel_export.h // #pragma mark - fssh_kernel_export.h
/* kernel threads */ /* kernel threads */
#define spawn_kernel_thread fssh_spawn_kernel_thread #define spawn_kernel_thread fssh_spawn_kernel_thread
/* misc */
#define user_memcpy fssh_user_memcpy
/* primitive kernel debugging facilities */ /* primitive kernel debugging facilities */
#define dprintf fssh_dprintf #define dprintf fssh_dprintf
#define kprintf fssh_kprintf #define kprintf fssh_kprintf

View File

@ -10,15 +10,18 @@
extern "C" { extern "C" {
#endif #endif
/*-------------------------------------------------------------*/
/* kernel threads */ /* kernel threads */
extern fssh_thread_id fssh_spawn_kernel_thread(fssh_thread_func function, extern fssh_thread_id fssh_spawn_kernel_thread(fssh_thread_func function,
const char *threadName, int32_t priority, const char *threadName, int32_t priority,
void *arg); void *arg);
/* misc */
extern fssh_status_t fssh_user_memcpy(void *dest, const void *source,
fssh_size_t length);
/*-------------------------------------------------------------*/
/* primitive kernel debugging facilities */ /* primitive kernel debugging facilities */
extern void fssh_dprintf(const char *format, ...) /* just like printf */ extern void fssh_dprintf(const char *format, ...) /* just like printf */

View File

@ -78,13 +78,13 @@ DeviceOpener::~DeviceOpener()
int int
DeviceOpener::Open(const char *device, int mode) DeviceOpener::Open(const char *device, int mode)
{ {
fDevice = open(device, mode); fDevice = open(device, mode | O_NOCACHE);
if (fDevice < 0) if (fDevice < 0)
fDevice = errno; fDevice = errno;
if (fDevice < 0 && mode == O_RDWR) { if (fDevice < 0 && mode == O_RDWR) {
// try again to open read-only (don't rely on a specific error code) // try again to open read-only (don't rely on a specific error code)
return Open(device, O_RDONLY); return Open(device, O_RDONLY | O_NOCACHE);
} }
if (fDevice >= 0) { if (fDevice >= 0) {
@ -97,7 +97,7 @@ DeviceOpener::Open(const char *device, int mode)
if (geometry.read_only) { if (geometry.read_only) {
// reopen device read-only // reopen device read-only
close(fDevice); close(fDevice);
return Open(device, O_RDONLY); return Open(device, O_RDONLY | O_NOCACHE);
} }
} }
} }
@ -203,7 +203,8 @@ disk_super_block::IsValid()
void void
disk_super_block::Initialize(const char *diskName, off_t numBlocks, uint32 blockSize) disk_super_block::Initialize(const char *diskName, off_t numBlocks,
uint32 blockSize)
{ {
memset(this, 0, sizeof(disk_super_block)); memset(this, 0, sizeof(disk_super_block));
@ -312,7 +313,8 @@ Volume::Mount(const char *deviceName, uint32 flags)
flags |= B_MOUNT_READ_ONLY; flags |= B_MOUNT_READ_ONLY;
#endif #endif
DeviceOpener opener(deviceName, flags & B_MOUNT_READ_ONLY ? O_RDONLY : O_RDWR); DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0
? O_RDONLY : O_RDWR);
fDevice = opener.Device(); fDevice = opener.Device();
if (fDevice < B_OK) if (fDevice < B_OK)
RETURN_ERROR(fDevice); RETURN_ERROR(fDevice);
@ -326,21 +328,6 @@ Volume::Mount(const char *deviceName, uint32 flags)
if (fstat(fDevice, &stat) < 0) if (fstat(fDevice, &stat) < 0)
RETURN_ERROR(B_ERROR); RETURN_ERROR(B_ERROR);
// TODO: allow turning off caching of the underlying file (once O_NOCACHE works)
#if 0
#ifndef NO_FILE_UNCACHED_IO
if ((stat.st_mode & S_FILE) != 0 && ioctl(fDevice, IOCTL_FILE_UNCACHED_IO, NULL) < 0) {
// mount read-only if the cache couldn't be disabled
# ifdef DEBUG
FATAL(("couldn't disable cache for image file - system may dead-lock!\n"));
# else
FATAL(("couldn't disable cache for image file!\n"));
Panic();
# endif
}
#endif
#endif
// read the super block // read the super block
if (Identify(fDevice, &fSuperBlock) != B_OK) { if (Identify(fDevice, &fSuperBlock) != B_OK) {
FATAL(("invalid super block!\n")); FATAL(("invalid super block!\n"));
@ -383,11 +370,6 @@ Volume::Mount(const char *deviceName, uint32 flags)
if (status == B_OK) { if (status == B_OK) {
// try to get indices root dir // try to get indices root dir
// question: why doesn't get_vnode() work here??
// answer: we have not yet backpropagated the pointer to the
// volume in bfs_mount(), so bfs_read_vnode() can't get it.
// But it's not needed to do that anyway.
if (!Indices().IsZero()) if (!Indices().IsZero())
fIndicesNode = new Inode(this, ToVnode(Indices())); fIndicesNode = new Inode(this, ToVnode(Indices()));
@ -397,8 +379,8 @@ Volume::Mount(const char *deviceName, uint32 flags)
INFORM(("bfs: volume doesn't have indices!\n")); INFORM(("bfs: volume doesn't have indices!\n"));
if (fIndicesNode) { if (fIndicesNode) {
// if this is the case, the index root node is gone bad, and // if this is the case, the index root node is gone bad,
// BFS switch to read-only mode // and BFS switch to read-only mode
fFlags |= VOLUME_READ_ONLY; fFlags |= VOLUME_READ_ONLY;
delete fIndicesNode; delete fIndicesNode;
fIndicesNode = NULL; fIndicesNode = NULL;
@ -450,12 +432,14 @@ Volume::Sync()
status_t status_t
Volume::ValidateBlockRun(block_run run) Volume::ValidateBlockRun(block_run run)
{ {
if (run.AllocationGroup() < 0 || run.AllocationGroup() > (int32)AllocationGroups() if (run.AllocationGroup() < 0
|| run.AllocationGroup() > (int32)AllocationGroups()
|| run.Start() > (1UL << AllocationGroupShift()) || run.Start() > (1UL << AllocationGroupShift())
|| run.length == 0 || run.length == 0
|| uint32(run.Length() + run.Start()) > (1UL << AllocationGroupShift())) { || uint32(run.Length() + run.Start()) > (1UL << AllocationGroupShift())) {
Panic(); Panic();
FATAL(("*** invalid run(%d,%d,%d)\n", (int)run.AllocationGroup(), run.Start(), run.Length())); FATAL(("*** invalid run(%d,%d,%d)\n", (int)run.AllocationGroup(),
run.Start(), run.Length()));
return B_BAD_DATA; return B_BAD_DATA;
} }
return B_OK; return B_OK;
@ -466,8 +450,10 @@ block_run
Volume::ToBlockRun(off_t block) const Volume::ToBlockRun(off_t block) const
{ {
block_run run; block_run run;
run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(block >> AllocationGroupShift()); run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(
run.start = HOST_ENDIAN_TO_BFS_INT16(block & ((1LL << AllocationGroupShift()) - 1)); block >> AllocationGroupShift());
run.start = HOST_ENDIAN_TO_BFS_INT16(
block & ((1LL << AllocationGroupShift()) - 1));
run.length = HOST_ENDIAN_TO_BFS_INT16(1); run.length = HOST_ENDIAN_TO_BFS_INT16(1);
return run; return run;
} }
@ -489,16 +475,20 @@ Volume::CreateIndicesRoot(Transaction &transaction)
status_t status_t
Volume::AllocateForInode(Transaction &transaction, const Inode *parent, mode_t type, block_run &run) Volume::AllocateForInode(Transaction &transaction, const Inode *parent,
mode_t type, block_run &run)
{ {
return fBlockAllocator.AllocateForInode(transaction, &parent->BlockRun(), type, run); return fBlockAllocator.AllocateForInode(transaction, &parent->BlockRun(),
type, run);
} }
status_t status_t
Volume::WriteSuperBlock() Volume::WriteSuperBlock()
{ {
if (write_pos(fDevice, 512, &fSuperBlock, sizeof(disk_super_block)) != sizeof(disk_super_block)) // TODO: this assumes a block size of 512 bytes of the underlying device
if (write_pos(fDevice, 512, &fSuperBlock, sizeof(disk_super_block))
!= sizeof(disk_super_block))
return B_IO_ERROR; return B_IO_ERROR;
return B_OK; return B_OK;
@ -506,15 +496,18 @@ Volume::WriteSuperBlock()
void void
Volume::UpdateLiveQueries(Inode *inode, const char *attribute, int32 type, const uint8 *oldKey, Volume::UpdateLiveQueries(Inode *inode, const char *attribute, int32 type,
size_t oldLength, const uint8 *newKey, size_t newLength) const uint8 *oldKey, size_t oldLength, const uint8 *newKey,
size_t newLength)
{ {
if (fQueryLock.Lock() < B_OK) if (fQueryLock.Lock() < B_OK)
return; return;
Query *query = NULL; Query *query = NULL;
while ((query = fQueries.Next(query)) != NULL) while ((query = fQueries.Next(query)) != NULL) {
query->LiveUpdate(inode, attribute, type, oldKey, oldLength, newKey, newLength); query->LiveUpdate(inode, attribute, type, oldKey, oldLength, newKey,
newLength);
}
fQueryLock.Unlock(); fQueryLock.Unlock();
} }
@ -568,11 +561,10 @@ Volume::Identify(int fd, disk_super_block *superBlock)
if (read_pos(fd, 0, buffer, sizeof(buffer)) != sizeof(buffer)) if (read_pos(fd, 0, buffer, sizeof(buffer)) != sizeof(buffer))
return B_IO_ERROR; return B_IO_ERROR;
// Note: that does work only for x86, for PowerPC, the super block
// may be located at offset 0!
memcpy(superBlock, buffer + 512, sizeof(disk_super_block)); memcpy(superBlock, buffer + 512, sizeof(disk_super_block));
if (!superBlock->IsValid()) { if (!superBlock->IsValid()) {
#ifndef BFS_LITTLE_ENDIAN_ONLY #ifndef BFS_LITTLE_ENDIAN_ONLY
// For PPC, the super block might be located at offset 0
memcpy(superBlock, buffer, sizeof(disk_super_block)); memcpy(superBlock, buffer, sizeof(disk_super_block));
if (!superBlock->IsValid()) if (!superBlock->IsValid())
return B_BAD_VALUE; return B_BAD_VALUE;
@ -615,7 +607,7 @@ Volume::Initialize(int fd, const char *name, uint32 blockSize,
// create valid super block // create valid super block
fSuperBlock.Initialize(name, numBlocks, blockSize); fSuperBlock.Initialize(name, numBlocks, blockSize);
// initialize short hands to the super block (to save byte swapping) // initialize short hands to the super block (to save byte swapping)
fBlockSize = fSuperBlock.BlockSize(); fBlockSize = fSuperBlock.BlockSize();
fBlockShift = fSuperBlock.BlockShift(); fBlockShift = fSuperBlock.BlockShift();

View File

@ -1,6 +1,5 @@
/* bfs - BFS definitions and helper functions /*
* * Copyright 2001-2007, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
* Parts of this code is based on work previously done by Marcus Overhagen. * Parts of this code is based on work previously done by Marcus Overhagen.
* *
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
@ -8,6 +7,8 @@
#ifndef BFS_H #ifndef BFS_H
#define BFS_H #define BFS_H
//! BFS definitions and helper functions
#include "bfs_endian.h" #include "bfs_endian.h"
#include "system_dependencies.h" #include "system_dependencies.h"
@ -71,7 +72,9 @@ struct disk_super_block {
int32 magic3; int32 magic3;
inode_addr root_dir; inode_addr root_dir;
inode_addr indices; inode_addr indices;
int32 pad[8]; int32 _reserved[8];
int32 pad_to_block[87];
// this also contains parts of the boot block
int32 Magic1() const { return BFS_ENDIAN_TO_HOST_INT32(magic1); } int32 Magic1() const { return BFS_ENDIAN_TO_HOST_INT32(magic1); }
int32 Magic2() const { return BFS_ENDIAN_TO_HOST_INT32(magic2); } int32 Magic2() const { return BFS_ENDIAN_TO_HOST_INT32(magic2); }

View File

@ -16,6 +16,8 @@
*/ */
#define BFS_IOCTL_VERSION 14200 #define BFS_IOCTL_VERSION 14200
#define BFS_IOCTL_UPDATE_BOOT_BLOCK 14204
/* ioctls to use the "chkbfs" feature from the outside /* ioctls to use the "chkbfs" feature from the outside
* all calls use a struct check_result as single parameter * all calls use a struct check_result as single parameter
*/ */

View File

@ -576,6 +576,17 @@ bfs_ioctl(void *_fs, void *_node, void *_cookie, ulong cmd, void *buffer,
return allocator.CheckNextNode(control); return allocator.CheckNextNode(control);
} }
case BFS_IOCTL_UPDATE_BOOT_BLOCK:
{
// let's makebootable (or anyone else) update the boot block
// while BFS is mounted
if (user_memcpy(&volume->SuperBlock().pad_to_block,
(uint8 *)buffer + offsetof(disk_super_block, pad_to_block),
sizeof(volume->SuperBlock().pad_to_block)) < B_OK)
return B_BAD_ADDRESS;
return volume->WriteSuperBlock();
}
#ifdef DEBUG #ifdef DEBUG
case 56742: case 56742:
{ {

View File

@ -20,6 +20,14 @@ fssh_spawn_kernel_thread(fssh_thread_func function, const char *threadName,
} }
fssh_status_t
fssh_user_memcpy(void *dest, const void *source, fssh_size_t length)
{
memcpy(dest, source, length);
return FSSH_B_OK;
}
void void
fssh_dprintf(const char *format, ...) fssh_dprintf(const char *format, ...)
{ {
@ -65,6 +73,7 @@ fssh_panic(const char *format, ...)
*badAddress = 42; *badAddress = 42;
} }
void void
fssh_kernel_debugger(const char *message) fssh_kernel_debugger(const char *message)
{ {
@ -78,6 +87,7 @@ fssh_parse_expression(const char *string)
return 0; return 0;
} }
int int
fssh_add_debugger_command(char *name, fssh_debugger_command_hook hook, fssh_add_debugger_command(char *name, fssh_debugger_command_hook hook,
char *help) char *help)