From 166917c9cdf715d911f8de9415903718b075ee2c Mon Sep 17 00:00:00 2001 From: hyche Date: Tue, 29 Aug 2017 06:47:02 +0700 Subject: [PATCH] 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 --- .../kernel/file_systems/btrfs/Volume.cpp | 11 +++++ .../kernel/file_systems/btrfs/Volume.h | 2 + .../file_systems/btrfs/kernel_interface.cpp | 48 ++++++++++++++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp index 5a86ca2e22..2c6162358f 100644 --- a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp @@ -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) diff --git a/src/add-ons/kernel/file_systems/btrfs/Volume.h b/src/add-ons/kernel/file_systems/btrfs/Volume.h index 6ed1d3c027..a29a4ac41b 100644 --- a/src/add-ons/kernel/file_systems/btrfs/Volume.h +++ b/src/add-ons/kernel/file_systems/btrfs/Volume.h @@ -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]; diff --git a/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp index 2670215327..c3f20cd787 100644 --- a/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp @@ -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,