Skip to content

Commit

Permalink
fs: support xattr for extfs and subfs
Browse files Browse the repository at this point in the history
Signed-off-by: yuchen.cc <yuchen.cc@alibaba-inc.com>
  • Loading branch information
yuchen0cc committed Dec 13, 2023
1 parent 27ea983 commit 40e3410
Show file tree
Hide file tree
Showing 7 changed files with 440 additions and 34 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ if (PHOTON_ENABLE_FSTACK_DPDK)
target_include_directories(photon_obj PUBLIC ${FSTACK_INCLUDE_DIRS})
endif()
if (PHOTON_ENABLE_EXTFS)
target_include_directories(photon_obj PUBLIC ${LIBE2FS_INCLUDE_DIRS})
target_include_directories(photon_obj PUBLIC ${E2FS_INCLUDE_DIRS})
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0)
# This option is enabled by default after -std=c++17
Expand Down
239 changes: 222 additions & 17 deletions fs/extfs/extfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include "extfs.h"
#include <ext2fs/ext2fs.h>
#include <utime.h>
#include <errno.h>
#include <fcntl.h>
Expand Down Expand Up @@ -53,16 +54,14 @@ static ext2_filsys do_ext2fs_open(io_manager extfs_manager) {
&fs // ret_fs
);
if (ret) {
auto eno = errno = -parse_extfs_error(nullptr, 0, ret);
LOG_ERROR("failed ext2fs_open ", ERRNO(eno));
return nullptr;
errno = -parse_extfs_error(nullptr, 0, ret);
LOG_ERRNO_RETURN(0, nullptr, "failed ext2fs_open");
}
ret = ext2fs_read_bitmaps(fs);
if (ret) {
auto eno = errno = -parse_extfs_error(fs, 0, ret);
LOG_ERROR("failed ext2fs_read_bitmaps ", ERRNO(eno));
errno = -parse_extfs_error(fs, 0, ret);
ext2fs_close(fs);
return nullptr;
LOG_ERRNO_RETURN(0, nullptr, "failed ext2fs_read_bitmaps");
}
LOG_INFO("ext2fs opened");
return fs;
Expand Down Expand Up @@ -938,21 +937,12 @@ static int ino_iter_blocks(ext2_filsys fs, ext2_ino_t ino,
if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) {
LOG_DEBUG("ext2fs_inode_has_valid_blocks2");
return 0;
// return format->inline_data(&(inode.i_block[0]),
// format->private);
}

retval = ext2fs_extent_open(fs, ino, &extents);
if (retval == EXT2_ET_INODE_NOT_EXTENT) {
LOG_DEBUG("EXT2_ET_INODE_NOT_EXTENT");
return 0;
// retval = ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY,
// NULL, walk_block, pdata);
// if (retval) {
// com_err(__func__, retval, _("listing blocks of ino \"%u\""),
// ino);
// }
// return retval;
}

auto ret = ino_iter_extents(fs, ino, extents, blocks);
Expand All @@ -974,6 +964,183 @@ static int do_ext2fs_fiemap(ext2_filsys fs, ext2_ino_t ino, struct photon::fs::f
return 0;
}

static ssize_t do_ext2fs_getxattr(ext2_filsys fs, ext2_ino_t ino, const char *name, void *value,
size_t size) {
struct ext2_xattr_handle *h;
void *ptr;
size_t plen;
errcode_t ret = ext2fs_xattrs_open(fs, ino, &h);
if (ret)
return parse_extfs_error(fs, ino, ret);
DEFER(ext2fs_xattrs_close(&h));

ret = ext2fs_xattrs_read(h);
if (ret)
return parse_extfs_error(fs, ino, ret);
// get xattr
ret = ext2fs_xattr_get(h, name, &ptr, &plen);
if (ret)
return parse_extfs_error(fs, ino, ret);

if (size == 0) {
ret = plen;
} else if (size < plen) {
ret = -ERANGE;
} else {
memcpy(value, ptr, plen);
ret = plen;
}

ext2fs_free_mem(&ptr);
return ret;
}

static ssize_t do_ext2fs_getxattr(ext2_filsys fs, const char *path, const char *name,
void *value, size_t size, int follow) {
LOG_DEBUG(VALUE(path));
ext2_ino_t ino = string_to_inode(fs, path, follow);
if (!ino) return -ENOENT;

return do_ext2fs_getxattr(fs, ino, name, value, size);
}

static int count_buffer_space(char *name, char *value EXT2FS_ATTR((unused)),
size_t value_len EXT2FS_ATTR((unused)), void *data) {
auto cnt = (unsigned int *)data;
*cnt = *cnt + strlen(name) + 1;
return 0;
}

static int copy_names(char *name, char *value EXT2FS_ATTR((unused)),
size_t value_len EXT2FS_ATTR((unused)), void *data) {
auto buf = (char **)data;
size_t name_len = strlen(name);
memcpy(*buf, name, name_len + 1);
*buf = *buf + name_len + 1;
return 0;
}

static ssize_t do_ext2fs_listxattr(ext2_filsys fs, ext2_ino_t ino, char *list, size_t size) {
struct ext2_xattr_handle *h;
errcode_t ret = ext2fs_xattrs_open(fs, ino, &h);
if (ret)
return parse_extfs_error(fs, ino, ret);
DEFER(ext2fs_xattrs_close(&h));

ret = ext2fs_xattrs_read(h);
if (ret)
return parse_extfs_error(fs, ino, ret);
// count buffer space
unsigned int buf_size = 0;
ret = ext2fs_xattrs_iterate(h, count_buffer_space, &buf_size);
if (ret)
return parse_extfs_error(fs, ino, ret);

if (size == 0) {
return buf_size;
} else if (size < buf_size) {
return -ERANGE;
}
// copy to list
memset(list, 0, size);
ret = ext2fs_xattrs_iterate(h, copy_names, &list);
if (ret)
return parse_extfs_error(fs, ino, ret);

return buf_size;
}

static ssize_t do_ext2fs_listxattr(ext2_filsys fs, const char *path, char *list, size_t size, int follow) {
LOG_DEBUG(VALUE(path));
ext2_ino_t ino = string_to_inode(fs, path, follow);
if (!ino) return -ENOENT;

return do_ext2fs_listxattr(fs, ino, list, size);
}

static bool check_namespace(const char *name) {
static std::vector<std::string> valid_names = {
"gnu.",
"system.posix_acl_default",
"system.posix_acl_access",
"system.richacl",
"security.",
"trusted.",
"system.",
"user.",
};

for (auto &n : valid_names) {
if (strncmp(name, n.c_str(), n.size()) == 0) {
return true;
}
}
return false;
}

static int do_ext2fs_setxattr(ext2_filsys fs, ext2_ino_t ino, const char *name,
const void *value, size_t size, int flags) {
if (!check_namespace(name))
LOG_ERROR_RETURN(ENOTSUP, -ENOTSUP, "the namespace prefix of '`' is not valid", name);

struct ext2_xattr_handle *h;
errcode_t ret = ext2fs_xattrs_open(fs, ino, &h);
if (ret)
return parse_extfs_error(fs, ino, ret);
DEFER(ext2fs_xattrs_close(&h));

ret = ext2fs_xattrs_read(h);
if (ret)
return parse_extfs_error(fs, ino, ret);
// set xattr
ret = ext2fs_xattr_set(h, name, value, size);
if (ret)
return parse_extfs_error(fs, ino, ret);
// update_ctime
ret = update_xtime(fs, ino, nullptr, EXT_CTIME);
if (ret) return ret;

return 0;
}

static int do_ext2fs_setxattr(ext2_filsys fs, const char *path, const char *name,
const void *value, size_t size, int flags, int follow) {
LOG_DEBUG(VALUE(path));
ext2_ino_t ino = string_to_inode(fs, path, follow);
if (!ino) return -ENOENT;

return do_ext2fs_setxattr(fs, ino, name, value, size, flags);
}

static int do_ext2fs_removexattr(ext2_filsys fs, ext2_ino_t ino, const char *name) {
struct ext2_xattr_handle *h;
errcode_t ret = ext2fs_xattrs_open(fs, ino, &h);
if (ret)
return parse_extfs_error(fs, ino, ret);
DEFER(ext2fs_xattrs_close(&h));

ret = ext2fs_xattrs_read(h);
if (ret)
return parse_extfs_error(fs, ino, ret);
// remove xattr
// no key found is treat as success
ret = ext2fs_xattr_remove(h, name);
if (ret)
return parse_extfs_error(fs, ino, ret);
// update_ctime
ret = update_xtime(fs, ino, nullptr, EXT_CTIME);
if (ret) return ret;

return 0;
}

static int do_ext2fs_removexattr(ext2_filsys fs, const char *path, const char *name, int follow) {
LOG_DEBUG(VALUE(path));
ext2_ino_t ino = string_to_inode(fs, path, follow);
if (!ino) return -ENOENT;

return do_ext2fs_removexattr(fs, ino, name);
}

#define DO_EXT2FS(func) \
auto ret = func; \
Expand All @@ -986,8 +1153,10 @@ static int do_ext2fs_fiemap(ext2_filsys fs, ext2_ino_t ino, struct photon::fs::f
namespace photon {
namespace fs {

extern io_manager new_io_manager(photon::fs::IFile *file);

class ExtFileSystem;
class ExtFile : public photon::fs::VirtualFile {
class ExtFile : public photon::fs::VirtualFile, public photon::fs::IFileXAttr {
public:
ExtFile(ext2_file_t _file, int _flags, ExtFileSystem *_fs) :
file(_file), flags(_flags), m_fs(_fs) {
Expand Down Expand Up @@ -1045,6 +1214,18 @@ class ExtFile : public photon::fs::VirtualFile {
virtual int fiemap(struct photon::fs::fiemap* map) override {
DO_EXT2FS(do_ext2fs_fiemap(fs, ino, map));
}
virtual ssize_t fgetxattr(const char *name, void *value, size_t size) override {
DO_EXT2FS(do_ext2fs_getxattr(fs, ino, name, value, size));
}
virtual ssize_t flistxattr(char *list, size_t size) override {
DO_EXT2FS(do_ext2fs_listxattr(fs, ino, list, size));
}
virtual int fsetxattr(const char *name, const void *value, size_t size, int flags) override {
DO_EXT2FS(do_ext2fs_setxattr(fs, ino, name, value, size, flags));
}
virtual int fremovexattr(const char *name) override {
DO_EXT2FS(do_ext2fs_removexattr(fs, ino, name));
}

virtual photon::fs::IFileSystem *filesystem() override;

Expand Down Expand Up @@ -1103,7 +1284,7 @@ class ExtDIR : public photon::fs::DIR {
};

static const uint64_t kMinimalInoLife = 1L * 1000 * 1000; // ino lives at least 1s
class ExtFileSystem : public photon::fs::IFileSystem {
class ExtFileSystem : public photon::fs::IFileSystem, public photon::fs::IFileSystemXAttr {
public:
ext2_filsys fs;
io_manager extfs_io_manager;
Expand Down Expand Up @@ -1216,6 +1397,30 @@ class ExtFileSystem : public photon::fs::IFileSystem {
}
return flush_buffer();
}
ssize_t getxattr(const char *path, const char *name, void *value, size_t size) override {
DO_EXT2FS(do_ext2fs_getxattr(fs, path, name, value, size, 1));
}
ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size) override {
DO_EXT2FS(do_ext2fs_getxattr(fs, path, name, value, size, 0));
}
ssize_t listxattr(const char *path, char *list, size_t size) override {
DO_EXT2FS(do_ext2fs_listxattr(fs, path, list, size, 1));
}
ssize_t llistxattr(const char *path, char *list, size_t size) override {
DO_EXT2FS(do_ext2fs_listxattr(fs, path, list, size, 0));
}
int setxattr(const char *path, const char *name, const void *value, size_t size, int flags) override {
DO_EXT2FS(do_ext2fs_setxattr(fs, path, name, value, size, flags, 1));
}
int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) override {
DO_EXT2FS(do_ext2fs_setxattr(fs, path, name, value, size, flags, 0));
}
int removexattr(const char *path, const char *name) override {
DO_EXT2FS(do_ext2fs_removexattr(fs, path, name, 1));
}
int lremovexattr(const char *path, const char *name) override {
DO_EXT2FS(do_ext2fs_removexattr(fs, path, name, 0));
}

photon::fs::DIR *opendir(const char *path) override {
std::vector<::dirent> dirs;
Expand Down
4 changes: 1 addition & 3 deletions fs/extfs/extfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include <ext2fs/ext2fs.h>
#include <photon/fs/filesystem.h>

namespace photon {
namespace fs {

io_manager new_io_manager(photon::fs::IFile *file);
photon::fs::IFileSystem *new_extfs(photon::fs::IFile *file, bool buffer = true);

// make extfs on an prezeroed IFile,
// should be truncated to specified size in advance
int make_extfs(photon::fs::IFile *file, char *uuid = nullptr);

}
}
}
1 change: 1 addition & 0 deletions fs/extfs/extfs_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include "extfs.h"
#include <ext2fs/ext2fs.h>
#include <sys/stat.h>
#include <photon/common/alog.h>
#include <photon/common/callback.h>
Expand Down
5 changes: 4 additions & 1 deletion fs/extfs/mkfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ int do_mkfs(io_manager manager, size_t size, char *uuid) {
return ret;
}
// reserve inodes
ext2fs_inode_alloc_stats2(fs, EXT2_BAD_INO, +1, 0);
for (ext2_ino_t i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++)
ext2fs_inode_alloc_stats2(fs, i, +1, 0);
ext2fs_mark_ib_dirty(fs);
Expand All @@ -135,6 +136,8 @@ int do_mkfs(io_manager manager, size_t size, char *uuid) {
namespace photon {
namespace fs {

extern io_manager new_io_manager(photon::fs::IFile *file);

int make_extfs(photon::fs::IFile *file, char *uuid) {
struct stat st;
auto ret = file->fstat(&st);
Expand All @@ -148,4 +151,4 @@ int make_extfs(photon::fs::IFile *file, char *uuid) {
}

}
}
}
Loading

0 comments on commit 40e3410

Please sign in to comment.