// SPDX-License-Identifier: GPL-2.0 /* * fs/hmdfs/file_root.c * * Copyright (c) 2020-2021 Huawei Device Co., Ltd. */ #include <linux/fs_stack.h> #include <linux/mount.h> #include <linux/namei.h> #include "authority/authentication.h" #include "comm/socket_adapter.h" #include "comm/transport.h" #include "hmdfs.h" #include "hmdfs_dentryfile.h" #include "hmdfs_device_view.h" #define DEVICE_VIEW_CTX_POS 2 #define MERGE_VIEW_CTX_POS 3 #define CLOUD_MERGE_VIEW_CTX_POS 4 #define ROOT_DIR_INO_START 20000000 // used by hmdfs_device_iterate functions #define DEVICE_VIEW_INO_START 20000002 #define LOCAL_DEVICE_CTX_POS 2 #define CLOUD_DEVICE_CTX_POS 3 struct hmdfs_peer *get_next_con(struct hmdfs_sb_info *sbi, unsigned long current_dev_id) { struct hmdfs_peer *con = NULL; struct hmdfs_peer *next_con = NULL; struct list_head *head, *node; mutex_lock(&sbi->connections.node_lock); head = &sbi->connections.node_list; if (current_dev_id == 0) { node = head->next; if (node == head) goto done; next_con = container_of(node, struct hmdfs_peer, list); if (next_con->status == NODE_STAT_ONLINE) goto done; current_dev_id = next_con->device_id; next_con = NULL; } list_for_each_entry(con, &sbi->connections.node_list, list) { if ((con->device_id & 0xFFFF) == (current_dev_id & 0xFFFF)) { node = con->list.next; if (node == head) goto done; next_con = container_of(node, struct hmdfs_peer, list); if (next_con->status == NODE_STAT_ONLINE) goto done; current_dev_id = next_con->device_id; next_con = NULL; } } done: if (next_con) peer_get(next_con); mutex_unlock(&sbi->connections.node_lock); return next_con; } int hmdfs_device_iterate(struct file *file, struct dir_context *ctx) { int err = 0; uint64_t ino_start = DEVICE_VIEW_INO_START; struct hmdfs_peer *next_con = NULL; unsigned long dev_id = 0; struct hmdfs_peer *con = NULL; char *remote_device_name = NULL; if (ctx->pos != 0) goto out; dir_emit_dots(file, ctx); if (ctx->pos == LOCAL_DEVICE_CTX_POS) { err = dir_emit(ctx, DEVICE_VIEW_LOCAL, sizeof(DEVICE_VIEW_LOCAL) - 1, ino_start++, DT_DIR); if (!err) goto out; (ctx->pos)++; } if (ctx->pos == CLOUD_DEVICE_CTX_POS) { err = dir_emit(ctx, DEVICE_VIEW_CLOUD, sizeof(DEVICE_VIEW_CLOUD) - 1, ino_start++, DT_DIR); if (!err) goto out; (ctx->pos)++; } next_con = get_next_con(file->f_inode->i_sb->s_fs_info, 0); if (!next_con) goto out; dev_id = next_con->device_id; peer_put(next_con); con = hmdfs_lookup_from_devid(file->f_inode->i_sb->s_fs_info, dev_id); remote_device_name = kmalloc(HMDFS_CID_SIZE + 1, GFP_KERNEL); if (!remote_device_name) { err = -ENOMEM; goto out; } while (con) { peer_put(con); snprintf(remote_device_name, HMDFS_CID_SIZE + 1, "%s", con->cid); if (!dir_emit(ctx, remote_device_name, strlen(remote_device_name), ino_start++, DT_DIR)) goto done; (ctx->pos)++; con = get_next_con(file->f_inode->i_sb->s_fs_info, dev_id); if (!con) goto done; dev_id = con->device_id; } done: kfree(remote_device_name); out: if (err <= 0) ctx->pos = -1; return err; } int hmdfs_root_iterate(struct file *file, struct dir_context *ctx) { uint64_t ino_start = ROOT_DIR_INO_START; struct hmdfs_sb_info *sbi = file_inode(file)->i_sb->s_fs_info; if (!dir_emit_dots(file, ctx)) return 0; if (ctx->pos == DEVICE_VIEW_CTX_POS) { if (!dir_emit(ctx, DEVICE_VIEW_ROOT, sizeof(DEVICE_VIEW_ROOT) - 1, ino_start, DT_DIR)) return 0; ino_start++; ctx->pos = MERGE_VIEW_CTX_POS; } if (sbi->s_merge_switch && ctx->pos == MERGE_VIEW_CTX_POS) { if (!dir_emit(ctx, MERGE_VIEW_ROOT, sizeof(MERGE_VIEW_ROOT) - 1, ino_start, DT_DIR)) return 0; ino_start++; (ctx->pos)++; } if (sbi->s_merge_switch && ctx->pos == CLOUD_MERGE_VIEW_CTX_POS) { if (!dir_emit(ctx, CLOUD_MERGE_VIEW_ROOT, sizeof(CLOUD_MERGE_VIEW_ROOT) - 1, ino_start, DT_DIR)) return 0; ino_start++; (ctx->pos)++; } return 0; } const struct file_operations hmdfs_root_fops = { .owner = THIS_MODULE, .iterate = hmdfs_root_iterate, }; const struct file_operations hmdfs_device_fops = { .owner = THIS_MODULE, .iterate = hmdfs_device_iterate, };