BTRFS: Implement btrfs_create_dir that can create directories in most case.
We need to handle a case when node is full, the solution should be split or push data to another node. Signed-off-by: Augustin Cavalier <[email protected]>
This commit is contained in:
@@ -388,6 +388,17 @@ Volume::Mount(const char* deviceName, uint32 flags)
|
||||
fChecksumTree->SetRoot(root->LogicalAddress(), NULL);
|
||||
free(root);
|
||||
|
||||
search_key.SetObjectID(-1);
|
||||
search_key.SetType(0);
|
||||
status = fFSTree->FindPrevious(&path, search_key, NULL);
|
||||
if (status != B_OK) {
|
||||
ERROR("Volume::Mount() Couldn't find any inode!!\n");
|
||||
return status;
|
||||
}
|
||||
fLargestInodeID = search_key.ObjectID();
|
||||
TRACE("Volume::Mount() Find larget inode id % " B_PRIu64 "\n",
|
||||
fLargestInodeID);
|
||||
|
||||
// Initialize Journal
|
||||
fJournal = new(std::nothrow) Journal(this);
|
||||
if (fJournal == NULL)
|
||||
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
uint32 MaxInlineSize() const
|
||||
{ return fSectorSize / 2; }
|
||||
uint32 BlockSize() const { return fBlockSize; }
|
||||
ino_t GetNextInodeID() { return ++fLargestInodeID; }
|
||||
Chunk* SystemChunk() const { return fChunk; }
|
||||
Journal* GetJournal() const { return fJournal; }
|
||||
ExtentAllocator* GetAllocator() const { return fExtentAllocator; }
|
||||
@@ -72,6 +73,7 @@ private:
|
||||
mutex fLock;
|
||||
fs_volume* fFSVolume;
|
||||
int fDevice;
|
||||
ino_t fLargestInodeID;
|
||||
btrfs_super_block fSuperBlock;
|
||||
char fName[32];
|
||||
|
||||
|
||||
@@ -482,6 +482,52 @@ btrfs_read_link(fs_volume* _volume, fs_vnode* _node, char* buffer,
|
||||
// #pragma mark - Directory functions
|
||||
|
||||
|
||||
static status_t
|
||||
btrfs_create_dir(fs_volume* _volume, fs_vnode* _directory, const char* name,
|
||||
int mode)
|
||||
{
|
||||
Volume* volume = (Volume*)_volume->private_volume;
|
||||
Inode* directory = (Inode*)_directory->private_node;
|
||||
BTree::Path path(volume->FSTree());
|
||||
|
||||
if (volume->IsReadOnly())
|
||||
return B_READ_ONLY_DEVICE;
|
||||
|
||||
if (!directory->IsDirectory())
|
||||
return B_NOT_A_DIRECTORY;
|
||||
|
||||
status_t status = directory->CheckPermissions(W_OK);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
Transaction transaction(volume);
|
||||
ino_t id = volume->GetNextInodeID();
|
||||
mode = S_DIRECTORY | (mode & S_IUMSK);
|
||||
Inode* inode = Inode::Create(transaction, id, directory, mode);
|
||||
if (inode == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status = inode->Insert(transaction, &path);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status = inode->MakeReference(transaction, &path, directory, name, mode);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
put_vnode(volume->FSVolume(), inode->ID());
|
||||
entry_cache_add(volume->ID(), directory->ID(), name, inode->ID());
|
||||
|
||||
status = transaction.Done();
|
||||
if (status == B_OK)
|
||||
notify_entry_created(volume->ID(), directory->ID(), name, inode->ID());
|
||||
else
|
||||
entry_cache_remove(volume->ID(), directory->ID(), name);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
btrfs_open_dir(fs_volume* /*_volume*/, fs_vnode* _node, void** _cookie)
|
||||
{
|
||||
@@ -814,7 +860,7 @@ fs_vnode_ops gBtrfsVnodeOps = {
|
||||
NULL, // fs_write,
|
||||
|
||||
/* directory operations */
|
||||
NULL, // fs_create_dir,
|
||||
&btrfs_create_dir,
|
||||
NULL, // fs_remove_dir,
|
||||
&btrfs_open_dir,
|
||||
&btrfs_close_dir,
|
||||
|
||||
Reference in New Issue
Block a user