linux_dsm_epyc7002/fs/btrfs/syno-feat-tree.c
AuxXxilium 5fa3ea047a init: add dsm gpl source
Signed-off-by: AuxXxilium <info@auxxxilium.tech>
2024-07-05 18:00:04 +02:00

368 lines
8.9 KiB
C

#ifndef MY_ABC_HERE
#define MY_ABC_HERE
#endif
/*
* Copyright (C) 2020 Synology Inc. All rights reserved.
*/
#include "ctree.h"
#include "xattr.h"
#include "transaction.h"
#include "btrfs_inode.h"
#include "syno-feat-tree.h"
#include "disk-io.h"
#include "locking.h"
static inline int syno_feat_tree_update_helper(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_key *key,
u32 data_size)
{
int ret;
ret = btrfs_search_slot(trans, root, key, path, 0, 1);
if (ret > 0) {
btrfs_release_path(path);
// insert new item
ret = btrfs_insert_empty_item(trans, root, path, key, data_size);
}
return ret;
}
static int __btrfs_create_syno_feat_tree(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info)
{
int ret;
struct btrfs_root *syno_feat_root;
syno_feat_root = btrfs_create_tree(trans, BTRFS_SYNO_FEATURE_TREE_OBJECTID);
if (IS_ERR(syno_feat_root)) {
ret = PTR_ERR(syno_feat_root);
goto out;
}
fs_info->syno_feat_root = syno_feat_root;
ret = 0;
out:
return ret;
}
static int btrfs_syno_feat_tree_status_update(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info)
{
int ret;
struct btrfs_root *root = fs_info->syno_feat_root;
struct btrfs_path *path;
struct btrfs_key key;
int data_size;
struct extent_buffer *leaf;
struct btrfs_syno_feat_tree_status_item *ei;
if (!btrfs_syno_check_feat_tree_enable(fs_info))
return 0;
path = btrfs_alloc_path();
if (!path) {
ret = -ENOMEM;
goto out;
}
key.objectid = BTRFS_SYNO_FEAT_TREE_STATUS_OBJECTID;
key.type = SYNO_BTRFS_FEAT_TREE_STATUS_KEY;
key.offset = 0;
data_size = sizeof(struct btrfs_syno_feat_tree_status_item);
ret = syno_feat_tree_update_helper(trans, root, path, &key, data_size);
if (ret < 0)
goto out;
leaf = path->nodes[0];
ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_feat_tree_status_item);
btrfs_set_syno_feat_tree_status_version(leaf, ei, fs_info->syno_feat_tree_status.version);
btrfs_set_syno_feat_tree_status_status(leaf, ei, fs_info->syno_feat_tree_status.status);
btrfs_mark_buffer_dirty(path->nodes[0]);
out:
if (ret)
btrfs_abort_transaction(trans, ret);
btrfs_free_path(path);
return ret;
}
static int btrfs_create_syno_feat_tree(struct btrfs_fs_info *fs_info)
{
struct btrfs_trans_handle *trans = NULL;
struct btrfs_root *tree_root = fs_info->tree_root;
int ret;
trans = btrfs_start_transaction(tree_root, 3);
if (IS_ERR(trans)) {
return PTR_ERR(trans);
}
/* root item x 1 + root node x 1 */
ret = __btrfs_create_syno_feat_tree(trans, fs_info);
if (ret) {
btrfs_err(fs_info, "failed to create syno feature tree, ret=[%d]", ret);
goto out;
}
btrfs_syno_set_feat_tree_enable(fs_info);
/* tree item x 1 */
ret = btrfs_syno_feat_tree_status_update(trans, fs_info);
if (ret) {
btrfs_err(fs_info, "failed to update status of syno feature tree at the first time, ret=[%d]", ret);
btrfs_syno_set_feat_tree_disable(fs_info);
goto out;
}
return btrfs_commit_transaction(trans);
out:
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
return ret;
}
int btrfs_syno_feat_tree_enable(struct btrfs_fs_info *fs_info)
{
int ret = -1;
if (btrfs_syno_check_feat_tree_enable(fs_info)) {
ret = 0;
goto out;
}
#ifdef MY_ABC_HERE
/*
* Don't clean up existing feature-tree
*/
#else
btrfs_syno_set_feat_tree_disable(fs_info);
// clean up old tree
if (fs_info->syno_feat_root) {
btrfs_err(fs_info, "we are going to clean up syno feature tree because the status is not enabled");
ret = btrfs_syno_feat_tree_disable(fs_info);
if (ret) {
btrfs_err(fs_info, "failed to disable and clean up syno feature tree, ret: [%d].", ret);
goto out;
}
}
#endif /* MY_ABC_HERE */
ret = btrfs_create_syno_feat_tree(fs_info);
if (ret) {
btrfs_err(fs_info, "failed to create syno feature tree, ret: [%d].", ret);
goto out;
}
ret = 0;
out:
return ret;
}
static inline int syno_feat_tree_need_stop(struct btrfs_fs_info *fs_info)
{
return sb_rdonly(fs_info->sb) || btrfs_fs_closing(fs_info);
}
#ifdef MY_ABC_HERE
/*
* locker will store information in feature-tree, and we cannot provide any
* abilities to remove feature-tree.
*/
#else
static int btrfs_clear_syno_feat_tree(struct btrfs_fs_info *fs_info)
{
struct btrfs_trans_handle *trans;
struct btrfs_root *root = fs_info->syno_feat_root;
struct btrfs_path *path;
struct btrfs_key key;
int nr;
int ret;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
key.objectid = 0;
key.type = 0;
key.offset = 0;
while (1) {
trans = btrfs_start_transaction_fallback_global_rsv(root, 1);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
}
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
if (ret < 0)
goto end_trans;
nr = btrfs_header_nritems(path->nodes[0]);
if (!nr)
break;
path->slots[0] = 0;
ret = btrfs_del_items(trans, root, path, 0, nr);
if (ret) {
btrfs_err(root->fs_info, "failed to delete item of syno feature tree, ret: [%d].", ret);
goto end_trans;
}
btrfs_release_path(path);
ret = btrfs_end_transaction_throttle(trans);
if (ret)
goto out;
trans = NULL;
if (syno_feat_tree_need_stop(root->fs_info)) {
ret = -EAGAIN;
btrfs_debug(root->fs_info, "drop tree early exit, ret: [%d].", ret);
goto out;
}
if (fatal_signal_pending(current)) {
btrfs_debug(root->fs_info, "catch interrupt singal as cleaning up syno feature tree.");
ret = -EINTR;
goto out;
}
}
ret = 0;
end_trans:
if (trans)
btrfs_end_transaction_throttle(trans);
out:
btrfs_free_path(path);
return ret;
}
static int btrfs_delete_syno_feat_tree_root(struct btrfs_fs_info *fs_info)
{
struct btrfs_trans_handle *trans;
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *syno_feat_root = fs_info->syno_feat_root;
int ret;
trans = btrfs_start_transaction(tree_root, 0);
if (IS_ERR(trans))
return PTR_ERR(trans);
fs_info->syno_feat_root = NULL;
ret = btrfs_del_root(trans, &syno_feat_root->root_key);
if (ret) {
btrfs_err(fs_info, "failed to delete the root item about syno feature tree, ret: [%d].", ret);
goto abort;
}
list_del(&syno_feat_root->dirty_list);
btrfs_tree_lock(syno_feat_root->node);
btrfs_clean_tree_block(syno_feat_root->node);
btrfs_tree_unlock(syno_feat_root->node);
btrfs_free_tree_block(trans, syno_feat_root, syno_feat_root->node, 0, 1);
btrfs_put_root(syno_feat_root);
return btrfs_commit_transaction(trans);
abort:
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
return ret;
}
int btrfs_syno_feat_tree_disable(struct btrfs_fs_info *fs_info)
{
int ret;
if (!fs_info->syno_feat_root) {
ret = 0;
goto out;
}
btrfs_syno_set_feat_tree_disable(fs_info);
ret = btrfs_clear_syno_feat_tree(fs_info);
if (ret) {
btrfs_err(fs_info, "failed to clean up syno feature tree, ret: [%d].", ret);
goto out;
}
ret = btrfs_delete_syno_feat_tree_root(fs_info);
if (ret) {
btrfs_err(fs_info, "failed to delete syno feature tree root, ret: [%d].", ret);
goto out;
}
btrfs_info(fs_info, "have finished to clean up syno feature tree, ret: [%d].", ret);
ret = 0;
out:
return ret;
}
#endif /* MY_ABC_HERE */
int btrfs_syno_feat_tree_load_status_from_disk(struct btrfs_fs_info *fs_info)
{
struct btrfs_root *root = fs_info->syno_feat_root;
struct btrfs_path *path;
struct extent_buffer *leaf;
struct btrfs_syno_feat_tree_status_item *ei;
struct btrfs_key key;
struct btrfs_key found_key;
int ret;
if (!fs_info->syno_feat_root) {
btrfs_info(fs_info, "root of syno feature tree is null");
return 0;
}
path = btrfs_alloc_path();
if (!path) {
btrfs_err(fs_info, "failed to allocate path, err: [%ld]", PTR_ERR(path));
ret = -ENOMEM;
goto out;
}
key.objectid = BTRFS_SYNO_FEAT_TREE_STATUS_OBJECTID;
key.type = SYNO_BTRFS_FEAT_TREE_STATUS_KEY;
key.offset = 0;
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0) {
btrfs_err(fs_info, "failed to search slot on syno feature tree, ret: [%d].", ret);
goto out;
} else if (ret > 0) { /* tree empty */
btrfs_warn(fs_info, "feature tree is empty.");
ret = 0;
goto out;
}
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_feat_tree_status_item);
fs_info->syno_feat_tree_status.version = btrfs_syno_feat_tree_status_version(leaf, ei);
fs_info->syno_feat_tree_status.status = btrfs_syno_feat_tree_status_status(leaf, ei);
switch(fs_info->syno_feat_tree_status.status) {
case SYNO_FEAT_TREE_ST_ENABLE:
btrfs_info(fs_info, "syno feature tree is enabled");
break;
case SYNO_FEAT_TREE_ST_DISABLE:
btrfs_warn(fs_info, "disable status [%llx] has detected. We are going to clean up feautre tree.", fs_info->syno_feat_tree_status.status);
break;
default:
btrfs_err(fs_info, "invalid status [%llx] of syno feature tree has detected.", fs_info->syno_feat_tree_status.status);
break;
}
ret = 0;
out:
btrfs_free_path(path);
return ret;
}