diff --git a/.github/utest/configs/rtsmart/rtsmart.cfg b/.github/utest/configs/rtsmart/rtsmart.cfg index efc60640796e..7e7a36b3d9d0 100644 --- a/.github/utest/configs/rtsmart/rtsmart.cfg +++ b/.github/utest/configs/rtsmart/rtsmart.cfg @@ -2,5 +2,7 @@ CONFIG_RT_UTEST_MEMHEAP=y # dependencies CONFIG_RT_USING_SMART=y +CONFIG_RT_USING_LIBC=y +CONFIG_RT_USING_MUSLLIBC=y CONFIG_RT_USING_MEMHEAP=y CONFIG_RT_USING_DFS_V2=y diff --git a/.github/workflows/bsp_buildings.yml b/.github/workflows/bsp_buildings.yml index 0792d9fdf31d..e3cb6bc157ad 100644 --- a/.github/workflows/bsp_buildings.yml +++ b/.github/workflows/bsp_buildings.yml @@ -300,8 +300,8 @@ jobs: wget -q https://github.com/RT-Thread/toolchains-ci/releases/download/v1.7/arm-linux-musleabi_for_x86_64-pc-linux-gnu_stable.tar.bz2 sudo tar xjf arm-linux-musleabi_for_x86_64-pc-linux-gnu_stable.tar.bz2 -C /opt /opt/arm-linux-musleabi_for_x86_64-pc-linux-gnu/bin/arm-linux-musleabi-gcc --version - echo "RTT_EXEC_PATH=/opt/arm-linux-musleabi_for_x86_64-pc-linux-gnu/bin" >> $GITHUB_ENV - echo "RTT_CC_PREFIX=arm-linux-musleabi-" >> $GITHUB_ENV + echo "RTT_SMART_EXEC_PATH=/opt/arm-linux-musleabi_for_x86_64-pc-linux-gnu/bin" >> $GITHUB_ENV + echo "RTT_SMART_CC_PREFIX=arm-linux-musleabi-" >> $GITHUB_ENV - name: Install Simulator Tools if: ${{ matrix.legs.RTT_TOOL_CHAIN == 'gcc' && success() }} diff --git a/bsp/qemu-vexpress-a9/.ci/attachconfig/ci.attachconfig.yml b/bsp/qemu-vexpress-a9/.ci/attachconfig/ci.attachconfig.yml index ee74be04f3f6..a6cd2d8a3225 100644 --- a/bsp/qemu-vexpress-a9/.ci/attachconfig/ci.attachconfig.yml +++ b/bsp/qemu-vexpress-a9/.ci/attachconfig/ci.attachconfig.yml @@ -60,5 +60,7 @@ rt_smart.base: echo $RTT_CC_PREFIX kconfig: - CONFIG_RT_USING_SMART=y + - CONFIG_RT_USING_LIBC=y + - CONFIG_RT_USING_MUSLLIBC=y - CONFIG_RT_USING_MEMHEAP=y - CONFIG_RT_USING_DFS_V2=y diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c b/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c index 6f4983299280..ca3a8dc48acb 100644 --- a/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c @@ -18,11 +18,19 @@ #include -static void *seq_start(struct dfs_seq_file *seq, off_t *index) +#if defined(__aarch64__) || defined(__AARCH64EL__) +static rt_uint64_t cpu_midr(void) { - off_t i = *index; // seq->index + rt_uint64_t value; - return NULL + (i == 0); + __asm__ volatile("mrs %0, midr_el1" : "=r"(value)); + return value; +} +#endif + +static void *seq_start(struct dfs_seq_file *seq, off_t *index) +{ + return (*index < RT_CPUS_NR) ? (void *)1 : RT_NULL; } static void seq_stop(struct dfs_seq_file *seq, void *data) @@ -31,27 +39,57 @@ static void seq_stop(struct dfs_seq_file *seq, void *data) static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index) { - /* data: The return value of the start or next*/ - off_t i = *index + 1; // seq->index - - *index = i; - - return NULL; + RT_UNUSED(seq); + RT_UNUSED(data); + *index += 1; + return (*index < RT_CPUS_NR) ? (void *)1 : RT_NULL; } static int seq_show(struct dfs_seq_file *seq, void *data) { - /* data: The return value of the start or next*/ - dfs_seq_puts(seq, "rt_weak const struct dfs_seq_ops *cpuinfo_get_seq_ops(void)\n--need your own function--\n"); +#if defined(__aarch64__) || defined(__AARCH64EL__) + rt_uint64_t midr; + rt_uint32_t implementer; + rt_uint32_t variant; + rt_uint32_t architecture; + rt_uint32_t part; + rt_uint32_t revision; +#endif + + RT_UNUSED(data); +#if defined(__aarch64__) || defined(__AARCH64EL__) + midr = cpu_midr(); + implementer = (rt_uint32_t)((midr >> 24) & 0xffU); + variant = (rt_uint32_t)((midr >> 20) & 0x0fU); + architecture = (rt_uint32_t)((midr >> 16) & 0x0fU); + part = (rt_uint32_t)((midr >> 4) & 0x0fffU); + revision = (rt_uint32_t)(midr & 0x0fU); +#endif + + dfs_seq_printf(seq, "processor\t: %lu\n", (unsigned long)seq->index); +#if defined(__aarch64__) || defined(__AARCH64EL__) + dfs_seq_puts(seq, "model name\t: ARMv8 Generic\n"); + dfs_seq_printf(seq, "CPU implementer\t: 0x%02lx\n", (unsigned long)implementer); + dfs_seq_printf(seq, "CPU architecture: %lu\n", (unsigned long)(architecture ? architecture : 8U)); + dfs_seq_printf(seq, "CPU variant\t: 0x%lx\n", (unsigned long)variant); + dfs_seq_printf(seq, "CPU part\t: 0x%03lx\n", (unsigned long)part); + dfs_seq_printf(seq, "CPU revision\t: %lu\n", (unsigned long)revision); +#elif defined(__riscv) + dfs_seq_puts(seq, "model name\t: RISC-V Generic\n"); + dfs_seq_puts(seq, "isa\t\t: rv64\n"); +#else + dfs_seq_puts(seq, "model name\t: RT-Thread Generic CPU\n"); +#endif + dfs_seq_puts(seq, "\n"); return 0; } static const struct dfs_seq_ops seq_ops = { - .start = seq_start, - .stop = seq_stop, - .next = seq_next, - .show = seq_show, + .start = seq_start, + .stop = seq_stop, + .next = seq_next, + .show = seq_show, }; rt_weak const struct dfs_seq_ops *cpuinfo_get_seq_ops(void) @@ -70,10 +108,10 @@ static int proc_close(struct dfs_file *file) } static const struct dfs_file_ops file_ops = { - .open = proc_open, - .read = dfs_seq_read, - .lseek = dfs_seq_lseek, - .close = proc_close, + .open = proc_open, + .read = dfs_seq_read, + .lseek = dfs_seq_lseek, + .close = proc_close, }; int proc_cpuinfo_init(void) diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c b/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c index 6ce1bc487a71..acb6ee35b563 100644 --- a/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c @@ -17,16 +17,62 @@ #include #include -#include +#ifdef RT_USING_SMART +#include "lwp_pid.h" +#ifdef RT_USING_MUSLLIBC +#include "lwp.h" +#endif +#endif -extern void rt_memory_info(rt_size_t *total, - rt_size_t *used, - rt_size_t *max_used); +#ifdef RT_USING_SMART +struct loadavg_count +{ + int total; + int runnable; +}; + +static int loadavg_count_pid(pid_t pid, void *arg) +{ + struct loadavg_count *count = (struct loadavg_count *)arg; + struct rt_lwp *lwp = lwp_from_pid_locked(pid); + + if (!lwp) + { + return 0; + } + count->total++; +#ifdef RT_USING_MUSLLIBC + { + rt_list_t *node; + + node = lwp->t_grp.next; + while (node != &lwp->t_grp) + { + rt_thread_t thread = rt_list_entry(node, struct rt_thread, sibling); + if (RT_SCHED_CTX(thread).stat == RT_THREAD_RUNNING) + { + count->runnable++; + break; + } + node = node->next; + } + } +#endif + return 0; +} +#endif static int single_show(struct dfs_seq_file *seq, void *data) { - dfs_seq_printf(seq, "0.13 0.16 0.17 1/1035 380436\n"); +#ifdef RT_USING_SMART + struct loadavg_count count = { 0, 0 }; + + lwp_pid_for_each(loadavg_count_pid, &count); + dfs_seq_printf(seq, "0.00 0.00 0.00 %d/%d 0\n", count.runnable, count.total); +#else + dfs_seq_puts(seq, "0.00 0.00 0.00 0/0 0\n"); +#endif return 0; } diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c b/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c index b6ae56288f4a..b1617f8bfd77 100644 --- a/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c @@ -34,24 +34,27 @@ static int single_show(struct dfs_seq_file *seq, void *data) total_sum = total_sum + total; total_freed = total_freed + total - used; - dfs_seq_printf(seq, "%-16s%8d KB\n", "MemMaxUsed:", max_used / 1024); - dfs_seq_printf(seq, "%-16s%8d KB\n", "MemAvailable:", (total - used) / 1024); - dfs_seq_printf(seq, "%-16s%8d KB\n", "Cached:", 0); - dfs_seq_printf(seq, "%-16s%8d KB\n", "SReclaimable:", 0); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemMaxUsed:", (unsigned long)(max_used / 1024)); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemAvailable:", (unsigned long)((total - used) / 1024)); rt_page_get_info(&total, &freed); total_sum = total_sum + total * RT_MM_PAGE_SIZE; total_freed = total_freed + freed * RT_MM_PAGE_SIZE; - dfs_seq_printf(seq, "%-16s%8d KB\n", "MemTotal:", total_sum / 1024); - dfs_seq_printf(seq, "%-16s%8d KB\n", "MemFree:", total_freed / 1024); - dfs_seq_printf(seq, "%-16s%8d KB\n", "LowPageTotal:", total * RT_MM_PAGE_SIZE / 1024); - dfs_seq_printf(seq, "%-16s%8d KB\n", "lowPageFree:", freed * RT_MM_PAGE_SIZE/ 1024); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemTotal:", (unsigned long)(total_sum / 1024)); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemFree:", (unsigned long)(total_freed / 1024)); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "Buffers:", 0UL); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "Cached:", 0UL); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "SwapCached:", 0UL); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "SwapTotal:", 0UL); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "SwapFree:", 0UL); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "LowPageTotal:", (unsigned long)(total * RT_MM_PAGE_SIZE / 1024)); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "LowPageFree:", (unsigned long)(freed * RT_MM_PAGE_SIZE / 1024)); rt_page_high_get_info(&total, &freed); - dfs_seq_printf(seq, "%-16s%8d KB\n", "HighPageTotal:", total * RT_MM_PAGE_SIZE / 1024); - dfs_seq_printf(seq, "%-16s%8d KB\n", "HighPageFree:", freed * RT_MM_PAGE_SIZE / 1024); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "HighPageTotal:", (unsigned long)(total * RT_MM_PAGE_SIZE / 1024)); + dfs_seq_printf(seq, "%-16s%8lu kB\n", "HighPageFree:", (unsigned long)(freed * RT_MM_PAGE_SIZE / 1024)); return 0; } diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c b/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c index 49a6ba99c6b0..1bb3b6a6bc6e 100644 --- a/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c @@ -19,13 +19,62 @@ #include #include +static void mnt_escape(const char *source, char *target, rt_size_t target_size) +{ + rt_size_t offset = 0; + const char *cursor = source ? source : ""; + + if (target_size == 0) + { + return; + } + + while (*cursor != '\0' && offset + 4 < target_size) + { + if (*cursor == ' ') + { + target[offset++] = '\\'; + target[offset++] = '0'; + target[offset++] = '4'; + target[offset++] = '0'; + } + else if (*cursor == '\t') + { + target[offset++] = '\\'; + target[offset++] = '0'; + target[offset++] = '1'; + target[offset++] = '1'; + } + else if (*cursor == '\n') + { + target[offset++] = '\\'; + target[offset++] = '0'; + target[offset++] = '1'; + target[offset++] = '2'; + } + else if (*cursor == '\\') + { + target[offset++] = '\\'; + target[offset++] = '1'; + target[offset++] = '3'; + target[offset++] = '4'; + } + else + { + target[offset++] = *cursor; + } + cursor++; + } + + target[offset] = '\0'; +} const char *mnt_flag(int flag) { - /*if (flag & MNT_READONLY) + if (flag & MNT_RDONLY) { return "ro"; - }*/ + } return "rw"; } @@ -33,19 +82,23 @@ const char *mnt_flag(int flag) static struct dfs_mnt* mnt_show(struct dfs_mnt *mnt, void *parameter) { struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter; + char source[DFS_PATH_MAX]; + char target[DFS_PATH_MAX]; + const char *source_name; + const char *filesystem_name; - if (mnt) + if (mnt && mnt->fs_ops && mnt->fullpath) { - if (mnt->dev_id) - { - dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->dev_id->parent.name, mnt->fullpath, - mnt->fs_ops->name, mnt_flag(mnt->flags)); - } - else + filesystem_name = mnt->fs_ops->name ? mnt->fs_ops->name : "unknown"; + source_name = filesystem_name; + if (mnt->dev_id && mnt->dev_id->parent.name[0] != '\0') { - dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->fs_ops->name, mnt->fullpath, - mnt->fs_ops->name, mnt_flag(mnt->flags)); + source_name = mnt->dev_id->parent.name; } + mnt_escape(source_name, source, sizeof(source)); + mnt_escape(mnt->fullpath, target, sizeof(target)); + dfs_seq_printf(seq, "%s %s %s %s 0 0\n", source, target, + filesystem_name, mnt_flag(mnt->flags)); } return RT_NULL; diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c b/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c index a413f646c830..9212351ac419 100644 --- a/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c @@ -26,6 +26,12 @@ #include "lwp.h" #include "lwp_pid.h" #include +#ifdef ARCH_MM_MMU +#include +#include +#include +#include +#endif struct pid_dentry { @@ -49,6 +55,241 @@ static char stat_transform(int __stat) } } +#ifdef ARCH_MM_MMU +#define PROC_MAP_MAX 256 + +struct proc_map_entry +{ + uintptr_t start; + uintptr_t end; + uintptr_t offset; + rt_size_t resident_pages; + rt_bool_t writable; + rt_bool_t shared; + rt_bool_t executable; + char name[DFS_PATH_MAX]; +}; + +struct proc_map_context +{ + struct rt_lwp *lwp; + struct proc_map_entry *entries; + rt_size_t count; + rt_bool_t smaps; +}; + +static void proc_map_permissions(rt_varea_t varea, struct proc_map_entry *entry) +{ + entry->writable = rt_hw_mmu_attr_test_perm( + varea->attr, RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER); + entry->shared = (varea->flag & MMF_MAP_SHARED) != 0; + entry->executable = (varea->flag & MMF_TEXT) != 0; +} + +static void proc_map_name(rt_varea_t varea, struct proc_map_entry *entry) +{ + const char *name = RT_NULL; + + if (varea->mem_obj && varea->mem_obj->get_name) + { + name = varea->mem_obj->get_name(varea); + } + + if (!name || !name[0] || !rt_strcmp(name, "anonymous") || + !rt_strcmp(name, "reference") || !rt_strcmp(name, "null")) + { + name = "[anon]"; + } + rt_strncpy(entry->name, name, sizeof(entry->name) - 1); + entry->name[sizeof(entry->name) - 1] = '\0'; +} + +static int proc_map_collect(rt_varea_t varea, void *arg) +{ + struct proc_map_context *context = (struct proc_map_context *)arg; + struct proc_map_entry *entry; + uintptr_t address; + uintptr_t end; + + if (context->count >= PROC_MAP_MAX || !varea || varea->size == 0) + { + return 0; + } + + entry = &context->entries[context->count++]; + entry->start = (uintptr_t)varea->start; + entry->end = entry->start + varea->size; + entry->offset = (uintptr_t)varea->offset * ARCH_PAGE_SIZE; + entry->resident_pages = 0; + proc_map_permissions(varea, entry); + proc_map_name(varea, entry); + + address = entry->start; + end = entry->end; + while (address < end) + { + if (rt_hw_mmu_v2p(varea->aspace, (void *)address) != ARCH_MAP_FAILED) + { + entry->resident_pages++; + } + address += ARCH_PAGE_SIZE; + } + + return 0; +} + +static void proc_map_context_free(struct proc_map_context *context) +{ + if (context) + { + if (context->lwp) + { + lwp_from_pid_release_lock(context->lwp); + } + if (context->entries) + { + rt_free(context->entries); + } + rt_free(context); + } +} + +static void *proc_maps_start(struct dfs_seq_file *seq, off_t *index) +{ + struct proc_map_context *context = (struct proc_map_context *)seq->data; + + return context && *index < (off_t)context->count ? &context->entries[*index] : RT_NULL; +} + +static void *proc_maps_next(struct dfs_seq_file *seq, void *data, off_t *index) +{ + struct proc_map_context *context = (struct proc_map_context *)seq->data; + + RT_UNUSED(data); + *index += 1; + return context && *index < (off_t)context->count ? &context->entries[*index] : RT_NULL; +} + +static void proc_maps_stop(struct dfs_seq_file *seq, void *data) +{ + RT_UNUSED(seq); + RT_UNUSED(data); +} + +static int proc_maps_show(struct dfs_seq_file *seq, void *data) +{ + struct proc_map_entry *entry = (struct proc_map_entry *)data; + char permissions[5]; + + permissions[0] = 'r'; + permissions[1] = entry->writable ? 'w' : '-'; + permissions[2] = entry->executable ? 'x' : '-'; + permissions[3] = entry->shared ? 's' : 'p'; + permissions[4] = '\0'; + + dfs_seq_printf(seq, "%0*lx-%0*lx %s %0*lx 00:00 0", + (int)(sizeof(uintptr_t) * 2), (unsigned long)entry->start, + (int)(sizeof(uintptr_t) * 2), (unsigned long)entry->end, + permissions, (int)(sizeof(uintptr_t) * 2), + (unsigned long)entry->offset); + if (entry->name[0]) + { + dfs_seq_printf(seq, " %s", entry->name); + } + dfs_seq_puts(seq, "\n"); + + if (((struct proc_map_context *)seq->data)->smaps) + { + rt_size_t resident_kb = entry->resident_pages * (ARCH_PAGE_SIZE / 1024); + rt_size_t private_dirty = entry->writable && !entry->shared ? resident_kb : 0; + + dfs_seq_printf(seq, "Size: %lu kB\n", (unsigned long)((entry->end - entry->start) / 1024)); + dfs_seq_printf(seq, "Rss: %lu kB\n", (unsigned long)resident_kb); + dfs_seq_printf(seq, "Pss: %lu kB\n", (unsigned long)resident_kb); + dfs_seq_puts(seq, "Shared_Clean: 0 kB\n"); + dfs_seq_puts(seq, "Shared_Dirty: 0 kB\n"); + dfs_seq_puts(seq, "Private_Clean: 0 kB\n"); + dfs_seq_printf(seq, "Private_Dirty: %lu kB\n", (unsigned long)private_dirty); + dfs_seq_printf(seq, "Anonymous: %lu kB\n", entry->name[0] == '[' ? (unsigned long)resident_kb : 0UL); + dfs_seq_puts(seq, "Swap: 0 kB\n\n"); + } + + return 0; +} + +static const struct dfs_seq_ops proc_maps_seq_ops = { + .start = proc_maps_start, + .stop = proc_maps_stop, + .next = proc_maps_next, + .show = proc_maps_show, +}; + +static int proc_maps_open(struct dfs_file *file) +{ + struct proc_dentry *dentry = (struct proc_dentry *)file->vnode->data; + struct proc_map_context *context; + struct dfs_seq_file *seq; + rt_varea_t varea; + int ret; + + context = rt_calloc(1, sizeof(*context)); + if (!context) + { + return -RT_ENOMEM; + } + context->lwp = lwp_from_pid_and_lock(dentry->pid); + if (!context->lwp || !context->lwp->aspace) + { + proc_map_context_free(context); + return -RT_ENOENT; + } + context->smaps = !rt_strcmp(dentry->name, "smaps"); + context->entries = rt_calloc(PROC_MAP_MAX, sizeof(*context->entries)); + if (!context->entries) + { + proc_map_context_free(context); + return -RT_ENOMEM; + } + + RD_LOCK(context->lwp->aspace); + varea = ASPACE_VAREA_FIRST(context->lwp->aspace); + while (varea) + { + proc_map_collect(varea, context); + varea = ASPACE_VAREA_NEXT(varea); + } + RD_UNLOCK(context->lwp->aspace); + + ret = dfs_seq_open(file, &proc_maps_seq_ops); + if (ret != RT_EOK) + { + proc_map_context_free(context); + return ret; + } + seq = (struct dfs_seq_file *)file->data; + seq->data = context; + return RT_EOK; +} + +static int proc_maps_close(struct dfs_file *file) +{ + struct dfs_seq_file *seq = (struct dfs_seq_file *)file->data; + struct proc_map_context *context = seq ? (struct proc_map_context *)seq->data : RT_NULL; + int ret = dfs_seq_release(file); + + proc_map_context_free(context); + file->data = RT_NULL; + return ret; +} + +static const struct dfs_file_ops proc_maps_fops = { + .open = proc_maps_open, + .read = dfs_seq_read, + .lseek = dfs_seq_lseek, + .close = proc_maps_close, +}; +#endif /* ARCH_MM_MMU */ + static int stat_single_show(struct dfs_seq_file *seq, void *data) { struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data; @@ -60,56 +301,53 @@ static int stat_single_show(struct dfs_seq_file *seq, void *data) int lwp_oncpu = RT_CPUS_NR; int lwp_oncpu_ok = 0; struct rt_lwp *lwp = RT_NULL; - char** argv = RT_NULL; + char **argv = RT_NULL; char *filename = RT_NULL; char *dot = RT_NULL; - lwp_pid_lock_take(); - - lwp = lwp_from_pid_locked(dentry->pid); - argv = lwp_get_command_line_args(lwp); + lwp = lwp_from_pid_and_lock(dentry->pid); + argv = lwp ? lwp_get_command_line_args(lwp) : RT_NULL; if (lwp) { - dfs_seq_printf(seq,"%d ",dentry->pid); + dfs_seq_printf(seq, "%d ", dentry->pid); if (argv) { - filename = strrchr(argv[0], '/'); - dot = strchr(argv[0], '.'); - - if (filename != NULL) + if (argv[0]) { - filename++; - } - else - { - filename = argv[0]; - } + filename = strrchr(argv[0], '/'); - if (dot != NULL) - { - *dot = '\0'; - } + if (filename != NULL) + { + filename++; + } + else + { + filename = argv[0]; + } - if (filename != NULL) - { - dfs_seq_printf(seq,"(%s) ", filename); + dot = strchr(filename, '.'); + if (dot != NULL) + { + *dot = '\0'; + } + + dfs_seq_printf(seq, "(%s) ", filename); } else { - dfs_seq_printf(seq,"(%s) ", argv[0]); + dfs_seq_printf(seq, "(%s) ", ""); } - lwp_free_command_line_args(argv); } else { - dfs_seq_printf(seq,"(%s) ", ""); + dfs_seq_printf(seq, "(%s) ", ""); } if (lwp->terminated) { - dfs_seq_printf(seq,"%c ",'Z'); + dfs_seq_printf(seq, "%c ", 'Z'); } else { @@ -120,11 +358,11 @@ static int stat_single_show(struct dfs_seq_file *seq, void *data) user_time_lwp = user_time_lwp + thread->user_time; system_time_lwp = system_time_lwp + thread->system_time; - #if RT_CPUS_NR > 1 - #define ONCPU(thread) RT_SCHED_CTX(thread).oncpu - #else - #define ONCPU(thread) 0 - #endif +#if RT_CPUS_NR > 1 +#define ONCPU(thread) RT_SCHED_CTX(thread).oncpu +#else +#define ONCPU(thread) 0 +#endif if (lwp_oncpu_ok == 0) { lwp_oncpu = ONCPU(thread); @@ -140,34 +378,37 @@ static int stat_single_show(struct dfs_seq_file *seq, void *data) if (mask == 1) { - dfs_seq_printf(seq,"%c ",'R'); + dfs_seq_printf(seq, "%c ", 'R'); } else { - dfs_seq_printf(seq,"%c ",'S'); + dfs_seq_printf(seq, "%c ", 'S'); } } - lwp_pid_lock_release(); - if (lwp->parent != NULL) - dfs_seq_printf(seq,"%d ",lwp->parent->pid); + { + dfs_seq_printf(seq, "%d ", lwp->parent->pid); + } else - dfs_seq_printf(seq,"0 "); + { + dfs_seq_printf(seq, "0 "); + } dfs_seq_printf(seq, "1 1 0 -1 4194560 48245 133976064 732 425574 "); - dfs_seq_printf(seq,"%llu ",user_time_lwp);//utime - dfs_seq_printf(seq,"%llu ",system_time_lwp);//stime + dfs_seq_printf(seq, "%llu ", user_time_lwp);//utime + dfs_seq_printf(seq, "%llu ", system_time_lwp);//stime dfs_seq_printf(seq, "1204291 518742 20 0 1 0 50 "); - dfs_seq_printf(seq, "%d ",rt_aspace_count_vsz(lwp->aspace));//VSZ +#ifdef ARCH_MM_MMU + dfs_seq_printf(seq, "%lu ", lwp->aspace ? (unsigned long)rt_aspace_count_vsz(lwp->aspace) : 0UL);//VSZ +#else + dfs_seq_puts(seq, "0 "); +#endif dfs_seq_printf(seq, "1422 18446744073709551615 "); dfs_seq_printf(seq, "1 1 0 0 0 0 671173123 4096 1260 0 0 0 17 "); dfs_seq_printf(seq, "%d ", lwp_oncpu);//CPU dfs_seq_printf(seq, "0 0 0 0 0 0 0 0 0 0 0 0 0"); - dfs_seq_printf(seq,"\n"); - } - else - { - lwp_pid_lock_release(); + dfs_seq_printf(seq, "\n"); + lwp_from_pid_release_lock(lwp); } return 0; @@ -177,12 +418,10 @@ static int cmdline_single_show(struct dfs_seq_file *seq, void *data) { struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data; struct rt_lwp *lwp; - char** argv; + char **argv; - lwp_pid_lock_take(); - lwp = lwp_from_pid_locked(dentry->pid); - argv = lwp_get_command_line_args(lwp); - lwp_pid_lock_release(); + lwp = lwp_from_pid_and_lock(dentry->pid); + argv = lwp ? lwp_get_command_line_args(lwp) : RT_NULL; if (argv) { @@ -198,10 +437,83 @@ static int cmdline_single_show(struct dfs_seq_file *seq, void *data) { dfs_seq_puts(seq, "error\n"); } + lwp_from_pid_release_lock(lwp); return 0; } +static int proc_pid_status_show(struct dfs_seq_file *seq, void *data) +{ + struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data; + struct rt_lwp *lwp = lwp_from_pid_and_lock(dentry->pid); + rt_size_t vm_size = 0; + rt_size_t thread_count = 0; + rt_list_t *node; + char state; + + RT_UNUSED(data); + if (!lwp) + { + return -RT_ENOENT; + } + +#ifdef ARCH_MM_MMU + if (lwp->aspace) + { + vm_size = rt_aspace_count_vsz(lwp->aspace); + } +#endif + node = lwp->t_grp.next; + while (node != &lwp->t_grp) + { + thread_count++; + node = node->next; + } + state = lwp->terminated ? 'Z' : 'S'; + dfs_seq_printf(seq, "Name:\t%s\n", lwp->cmd); + dfs_seq_printf(seq, "State:\t%c (sleeping)\n", state); + dfs_seq_printf(seq, "Pid:\t%d\n", lwp->pid); + dfs_seq_printf(seq, "PPid:\t%d\n", lwp->parent ? lwp->parent->pid : 0); + dfs_seq_puts(seq, "Uid:\t0\t0\t0\t0\nGid:\t0\t0\t0\t0\n"); + dfs_seq_printf(seq, "Threads:\t%lu\n", (unsigned long)thread_count); + dfs_seq_printf(seq, "VmSize:\t%lu kB\n", (unsigned long)(vm_size / 1024)); + dfs_seq_printf(seq, "VmRSS:\t%lu kB\n", (unsigned long)(vm_size / 1024)); + dfs_seq_puts(seq, "VmData:\t0 kB\nVmStk:\t0 kB\nVmExe:\t0 kB\nVmLib:\t0 kB\n"); + lwp_from_pid_release_lock(lwp); + return 0; +} + +static int proc_pid_statm_show(struct dfs_seq_file *seq, void *data) +{ + struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data; + struct rt_lwp *lwp = lwp_from_pid_and_lock(dentry->pid); + rt_size_t size_pages = 0; + rt_size_t text_pages = 0; + rt_size_t data_pages = 0; + + RT_UNUSED(data); + if (!lwp) + { + return -RT_ENOENT; + } + +#ifdef ARCH_MM_MMU + if (lwp->aspace) + { + size_pages = (rt_aspace_count_vsz(lwp->aspace) + ARCH_PAGE_SIZE - 1) / ARCH_PAGE_SIZE; + } +#endif +#ifdef ARCH_MM_MMU + text_pages = (lwp->text_size + ARCH_PAGE_SIZE - 1) / ARCH_PAGE_SIZE; + data_pages = (lwp->data_size + ARCH_PAGE_SIZE - 1) / ARCH_PAGE_SIZE; +#endif + dfs_seq_printf(seq, "%lu %lu 0 %lu 0 %lu 0\n", + (unsigned long)size_pages, (unsigned long)size_pages, + (unsigned long)text_pages, (unsigned long)data_pages); + lwp_from_pid_release_lock(lwp); + return 0; +} + struct proc_dentry *proc_pid_fd_lookup(struct proc_dentry *parent, const char *name) { struct proc_dentry *dentry = RT_NULL; @@ -240,13 +552,21 @@ struct proc_dentry *proc_pid_fd_lookup(struct proc_dentry *parent, const char *n { //todo add vnode->data if (file->vnode->type == FT_SOCKET) + { dentry->data = (void *)rt_strdup("socket"); + } else if (file->vnode->type == FT_USER) + { dentry->data = (void *)rt_strdup("user"); + } else if (file->vnode->type == FT_DEVICE) + { dentry->data = (void *)rt_strdup("device"); + } else + { dentry->data = (void *)rt_strdup("unknown"); + } } dentry->pid = parent->pid; @@ -337,8 +657,9 @@ int proc_pid_exe_readlink(struct proc_dentry *dentry, char *buf, int len) { struct rt_lwp *lwp; - lwp = lwp_self(); - len = rt_snprintf(buf, len, "%s", lwp ? lwp->exe_file : "null"); + lwp = lwp_from_pid_and_lock(dentry->pid); + len = rt_snprintf(buf, len, "%s", lwp && lwp->exe_file ? lwp->exe_file : "null"); + lwp_from_pid_release_lock(lwp); return len; } @@ -351,8 +672,9 @@ int proc_pid_cwd_readlink(struct proc_dentry *dentry, char *buf, int len) { struct rt_lwp *lwp; - lwp = lwp_self(); + lwp = lwp_from_pid_and_lock(dentry->pid); len = rt_snprintf(buf, len, "%s", lwp ? lwp->working_directory : "null"); + lwp_from_pid_release_lock(lwp); return len; } @@ -362,17 +684,23 @@ static const struct proc_ops proc_pid_cwd_ops = { }; static struct pid_dentry pid_dentry_base[] = { - {"cmdline", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, cmdline_single_show, 0}, - {"cwd", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_cwd_ops, 0, 0}, - {"exe", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_exe_ops, 0, 0}, - {"fd", S_IFDIR | S_IRUSR | S_IXUSR, &proc_pid_fd_fops, &proc_pid_fd_ops, 0, 0, 0}, - {"mounts", S_IFLNK | S_IRUSR | S_IXUSR, 0, 0, 0, 0, "/proc/mounts"}, - {"stat", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, stat_single_show, 0}, + { "cmdline", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, cmdline_single_show, 0 }, + { "status", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, proc_pid_status_show, 0 }, + { "statm", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, proc_pid_statm_show, 0 }, + { "cwd", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_cwd_ops, 0, 0 }, + { "exe", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_exe_ops, 0, 0 }, + { "fd", S_IFDIR | S_IRUSR | S_IXUSR, &proc_pid_fd_fops, &proc_pid_fd_ops, 0, 0, 0 }, + { "mounts", S_IFLNK | S_IRUSR | S_IXUSR, 0, 0, 0, 0, "/proc/mounts" }, + { "stat", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, stat_single_show, 0 }, +#ifdef ARCH_MM_MMU + { "maps", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, &proc_maps_fops, 0, 0, 0, 0 }, + { "smaps", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, &proc_maps_fops, 0, 0, 0, 0 }, +#endif }; int proc_pid(int pid) { - char pid_str[64] = {0}; + char pid_str[64] = { 0 }; struct proc_dentry *dentry; rt_snprintf(pid_str, 64, "%d", pid); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c b/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c index aeba99de5134..c24adb291e52 100644 --- a/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c @@ -18,6 +18,49 @@ #include +#ifdef RT_USING_SMART +#include "lwp_pid.h" +#ifdef RT_USING_MUSLLIBC +#include "lwp.h" +#endif +#endif + +#ifdef RT_USING_SMART +struct stat_process_count +{ + int total; + int running; +}; + +static int stat_process_count(pid_t pid, void *arg) +{ + struct stat_process_count *count = (struct stat_process_count *)arg; + struct rt_lwp *lwp = lwp_from_pid_locked(pid); + + if (!lwp) + { + return 0; + } + count->total++; +#ifdef RT_USING_MUSLLIBC + { + rt_list_t *node = lwp->t_grp.next; + + while (node != &lwp->t_grp) + { + rt_thread_t thread = rt_list_entry(node, struct rt_thread, sibling); + if (RT_SCHED_CTX(thread).stat == RT_THREAD_RUNNING) + { + count->running++; + break; + } + node = node->next; + } + } +#endif + return 0; +} +#endif static void *seq_start(struct dfs_seq_file *seq, off_t *index) { @@ -50,7 +93,7 @@ static int seq_show(struct dfs_seq_file *seq, void *data) for (i = 0; i < RT_CPUS_NR; i++) { - pcpu = rt_cpu_index(i); + pcpu = rt_cpu_index(i); user_total = user_total + pcpu->cpu_stat.user; system_total = system_total + pcpu->cpu_stat.system; idle_total = idle_total + pcpu->cpu_stat.idle; @@ -59,27 +102,36 @@ static int seq_show(struct dfs_seq_file *seq, void *data) for (i = 0; i < RT_CPUS_NR; i++) { - pcpu = rt_cpu_index(i); - dfs_seq_printf(seq, "cpu%d ",i); - dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.user);//user + pcpu = rt_cpu_index(i); + dfs_seq_printf(seq, "cpu%d ", i); + dfs_seq_printf(seq, "%llu ", pcpu->cpu_stat.user);//user dfs_seq_printf(seq, "0 ");//nice - dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.system);//system - dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.idle);//idle + dfs_seq_printf(seq, "%llu ", pcpu->cpu_stat.system);//system + dfs_seq_printf(seq, "%llu ", pcpu->cpu_stat.idle);//idle dfs_seq_printf(seq, "0 ");//iowait dfs_seq_printf(seq, "0 ");//irq dfs_seq_printf(seq, "0 ");//softirq dfs_seq_printf(seq, "0 0 0\n");//steal,guest,guest_nice + } +#ifdef RT_USING_SMART + { + struct stat_process_count process_count = { 0, 0 }; + lwp_pid_for_each(stat_process_count, &process_count); + dfs_seq_printf(seq, "processes %d\n", process_count.total); + dfs_seq_printf(seq, "procs_running %d\n", process_count.running); + dfs_seq_puts(seq, "procs_blocked 0\n"); } +#endif return 0; } static const struct dfs_seq_ops seq_ops = { - .start = seq_start, - .stop = seq_stop, - .next = seq_next, - .show = seq_show, + .start = seq_start, + .stop = seq_stop, + .next = seq_next, + .show = seq_show, }; rt_weak const struct dfs_seq_ops *stat_get_seq_ops(void) @@ -98,10 +150,10 @@ static int proc_close(struct dfs_file *file) } static const struct dfs_file_ops file_ops = { - .open = proc_open, - .read = dfs_seq_read, - .lseek = dfs_seq_lseek, - .close = proc_close, + .open = proc_open, + .read = dfs_seq_read, + .lseek = dfs_seq_lseek, + .close = proc_close, }; int proc_stat_init(void) diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c b/components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c index f16ab72b6672..5da9e9952d36 100644 --- a/components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c @@ -21,9 +21,26 @@ static int single_show(struct dfs_seq_file *seq, void *data) { - dfs_seq_printf(seq, "%lu.%02lu %lu.%02lu\n", - (unsigned long)rt_tick_get_millisecond() / 1000, (unsigned long)(rt_tick_get_millisecond() % 1000) / 100, - (unsigned long)rt_tick_get_millisecond() / 1000, (unsigned long)(rt_tick_get_millisecond() % 1000) / 100); + rt_tick_t ticks = rt_tick_get(); + rt_uint64_t uptime_ms; + rt_uint64_t idle_ticks = 0; +#ifdef RT_USING_SMP + int index; +#endif + + uptime_ms = ((rt_uint64_t)ticks * 1000U) / RT_TICK_PER_SECOND; +#ifdef RT_USING_SMP + for (index = 0; index < RT_CPUS_NR; index++) + { + idle_ticks += rt_cpu_index(index)->cpu_stat.idle; + } +#else + idle_ticks = rt_cpu_index(0)->cpu_stat.idle; +#endif + dfs_seq_printf(seq, "%llu.%02llu %llu.%02llu\n", + uptime_ms / 1000U, (uptime_ms % 1000U) / 10U, + ((rt_uint64_t)idle_ticks * 1000U) / RT_TICK_PER_SECOND / 1000U, + (((rt_uint64_t)idle_ticks * 1000U) / RT_TICK_PER_SECOND % 1000U) / 10U); return 0; } diff --git a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c index cc511415a3e2..0f1d42e9f860 100644 --- a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c +++ b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c @@ -25,8 +25,8 @@ #include "dfs_tmpfs.h" -#define DBG_TAG "tmpfs" -#define DBG_LVL DBG_INFO +#define DBG_TAG "tmpfs" +#define DBG_LVL DBG_INFO #include #ifdef RT_USING_PAGECACHE #include "dfs_pcache.h" @@ -36,20 +36,38 @@ static ssize_t dfs_tmp_page_read(struct dfs_file *file, struct dfs_page *page); static ssize_t dfs_tmp_page_write(struct dfs_page *page); -static struct dfs_aspace_ops dfs_tmp_aspace_ops = -{ +static struct dfs_aspace_ops dfs_tmp_aspace_ops = { .read = dfs_tmp_page_read, .write = dfs_tmp_page_write, }; #endif -static int _path_separate(const char *path, char *parent_path, char *file_name) +static int _tmpfs_path_validate(const char *path) +{ + if (path == RT_NULL || path[0] != '/') + { + return -EINVAL; + } + + return RT_EOK; +} + +static int _path_separate(const char *path, char *parent_path, rt_size_t parent_size, + char *file_name, rt_size_t file_size) { const char *path_p, *path_q; + rt_size_t parent_len, file_len; + int ret; - RT_ASSERT(path[0] == '/'); + ret = _tmpfs_path_validate(path); + if (ret != RT_EOK || parent_path == RT_NULL || file_name == RT_NULL || + parent_size < 2 || file_size == 0) + { + return ret != RT_EOK ? ret : -EINVAL; + } file_name[0] = '\0'; + parent_path[0] = '\0'; path_p = path_q = &path[1]; __next_dir: while (*path_q != '/' && *path_q != '\0') @@ -66,10 +84,17 @@ static int _path_separate(const char *path, char *parent_path, char *file_name) } else /* Last level dir */ { - rt_memcpy(parent_path, path, path_p - path - 1); - parent_path[path_p - path - 1] = '\0'; - rt_memcpy(file_name, path_p, path_q - path_p); - file_name[path_q - path_p] = '\0'; + parent_len = path_p - path - 1; + file_len = path_q - path_p; + if (parent_len >= parent_size || file_len >= file_size) + { + return -ENAMETOOLONG; + } + + rt_memcpy(parent_path, path, parent_len); + parent_path[parent_len] = '\0'; + rt_memcpy(file_name, path_p, file_len); + file_name[file_len] = '\0'; } } if (parent_path[0] == 0) @@ -83,18 +108,35 @@ static int _path_separate(const char *path, char *parent_path, char *file_name) return 0; } -static int _get_subdir(const char *path, char *name) +static int _get_subdir(const char *path, char *name, rt_size_t name_size) { const char *subpath = path; + rt_size_t name_len = 0; + + if (path == RT_NULL || name == RT_NULL || name_size == 0) + { + return -EINVAL; + } + while (*subpath == '/' && *subpath) - subpath ++; + { + subpath++; + } while (*subpath != '/' && *subpath) { + if (name_len + 1 >= name_size) + { + name[0] = '\0'; + return -ENAMETOOLONG; + } *name = *subpath; - name ++; - subpath ++; + name++; + subpath++; + name_len++; } - return 0; + *name = '\0'; + + return RT_EOK; } static int _free_subdir(struct tmpfs_file *dfile) @@ -143,6 +185,8 @@ static int dfs_tmpfs_mount(struct dfs_mnt *mnt, superblock->root.name[0] = '/'; superblock->root.sb = superblock; superblock->root.type = TMPFS_TYPE_DIR; + superblock->root.nlink = 1; + superblock->root.mode = S_IFDIR | (S_IRWXU | S_IRWXG | S_IRWXO); dfs_vfs_init_node(&superblock->root.node); rt_spin_lock_init(&superblock->lock); @@ -180,9 +224,9 @@ int dfs_tmpfs_statfs(struct dfs_mnt *mnt, struct statfs *buf) RT_ASSERT(superblock != NULL); RT_ASSERT(buf != NULL); - buf->f_bsize = 512; + buf->f_bsize = 512; buf->f_blocks = (superblock->df_size + 511) / 512; - buf->f_bfree = 1; + buf->f_bfree = 1; buf->f_bavail = buf->f_bfree; return RT_EOK; @@ -226,18 +270,28 @@ int dfs_tmpfs_ioctl(struct dfs_file *file, int cmd, void *args) return -EIO; } -struct tmpfs_file *dfs_tmpfs_lookup(struct tmpfs_sb *superblock, - const char *path, - rt_size_t *size) +struct tmpfs_file *dfs_tmpfs_lookup(struct tmpfs_sb *superblock, + const char *path, + rt_size_t *size) { const char *subpath, *curpath, *filename = RT_NULL; char subdir_name[TMPFS_NAME_MAX]; struct tmpfs_file *file, *curfile, *tmp; + int ret; + + ret = _tmpfs_path_validate(path); + if (ret != RT_EOK) + { + rt_set_errno(ret); + return RT_NULL; + } subpath = path; while (*subpath == '/' && *subpath) - subpath ++; - if (! *subpath) /* is root directory */ + { + subpath++; + } + if (!*subpath) /* is root directory */ { *size = 0; return &(superblock->root); @@ -248,15 +302,25 @@ struct tmpfs_file *dfs_tmpfs_lookup(struct tmpfs_sb *superblock, find_subpath: while (*subpath != '/' && *subpath) - subpath ++; + { + subpath++; + } - if (! *subpath) /* is last directory */ + if (!*subpath) /* is last directory */ + { filename = curpath; + } else - subpath ++; /* skip '/' */ + { + subpath++; /* skip '/' */ + } - memset(subdir_name, 0, TMPFS_NAME_MAX); - _get_subdir(curpath, subdir_name); + ret = _get_subdir(curpath, subdir_name, sizeof(subdir_name)); + if (ret != RT_EOK) + { + rt_set_errno(ret); + return RT_NULL; + } rt_spin_lock(&superblock->lock); @@ -297,12 +361,18 @@ static ssize_t dfs_tmpfs_read(struct dfs_file *file, void *buf, size_t count, of rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER); ssize_t size = (ssize_t)file->vnode->size; if ((ssize_t)count < size - *pos) + { length = count; + } else + { length = size - *pos; + } if (length > 0) + { memcpy(buf, &(d_file->data[*pos]), length); + } /* update file current position */ *pos += length; @@ -341,7 +411,9 @@ static ssize_t _dfs_tmpfs_write(struct tmpfs_file *d_file, const void *buf, size } if (count > 0) + { memcpy(d_file->data + *pos, buf, count); + } /* update file current position */ *pos += count; @@ -399,12 +471,16 @@ static int dfs_tmpfs_close(struct dfs_file *file) RT_ASSERT(file->vnode->ref_count > 0); if (file->vnode->ref_count != 1) + { return 0; + } d_file = (struct tmpfs_file *)file->vnode->data; if (d_file == NULL) + { return -ENOENT; + } if (d_file->fre_memory == RT_TRUE) { @@ -454,7 +530,7 @@ static int dfs_tmpfs_open(struct dfs_file *file) } RT_ASSERT(file->vnode->ref_count > 0); - if(file->vnode->ref_count == 1) + if (file->vnode->ref_count == 1) { dfs_vnode_lock_init(file->vnode, file->dentry); } @@ -472,29 +548,59 @@ static int dfs_tmpfs_stat(struct dfs_dentry *dentry, struct stat *st) d_file = dfs_tmpfs_lookup(superblock, dentry->pathname, &size); if (d_file == NULL) + { return -ENOENT; + } st->st_dev = (dev_t)(size_t)(dentry->mnt->dev_id); st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry); - if (d_file->type == TMPFS_TYPE_DIR) + st->st_mode = d_file->mode; + + st->st_size = d_file->size; + st->st_nlink = d_file->nlink; + st->st_mtime = 0; + + return RT_EOK; +} + +static int dfs_tmpfs_setattr(struct dfs_dentry *dentry, struct dfs_attr *attr) +{ + rt_size_t size; + struct tmpfs_file *d_file; + struct tmpfs_sb *superblock; + + if (dentry == RT_NULL || attr == RT_NULL || dentry->mnt == RT_NULL) { - st->st_mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + return -EINVAL; } - else + + superblock = (struct tmpfs_sb *)dentry->mnt->data; + d_file = dfs_tmpfs_lookup(superblock, dentry->pathname, &size); + if (d_file == RT_NULL) { - st->st_mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO); + return -ENOENT; } - st->st_size = d_file->size; - st->st_mtime = 0; + if (attr->ia_valid & ATTR_MODE_SET) + { + mode_t permissions = attr->st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + + rt_spin_lock(&superblock->lock); + d_file->mode = (d_file->mode & S_IFMT) | permissions; + if (dentry->vnode != RT_NULL) + { + dentry->vnode->mode = d_file->mode; + } + rt_spin_unlock(&superblock->lock); + } return RT_EOK; } static int dfs_tmpfs_getdents(struct dfs_file *file, - struct dirent *dirp, - uint32_t count) + struct dirent *dirp, + uint32_t count) { rt_size_t index, end; struct dirent *d; @@ -505,7 +611,7 @@ static int dfs_tmpfs_getdents(struct dfs_file *file, rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER); - superblock = d_file->sb; + superblock = d_file->sb; RT_ASSERT(superblock != RT_NULL); RT_UNUSED(superblock); @@ -539,9 +645,10 @@ static int dfs_tmpfs_getdents(struct dfs_file *file, { d->d_type = DT_SOCK; } - d->d_namlen = RT_NAME_MAX; + d->d_namlen = rt_strlen(n_file->name); d->d_reclen = (rt_uint16_t)sizeof(struct dirent); - rt_strncpy(d->d_name, n_file->name, TMPFS_NAME_MAX); + rt_strncpy(d->d_name, n_file->name, DIRENT_NAME_MAX); + d->d_name[DIRENT_NAME_MAX - 1] = '\0'; count += 1; file->fpos += 1; @@ -568,9 +675,12 @@ static int dfs_tmpfs_unlink(struct dfs_dentry *dentry) d_file = dfs_tmpfs_lookup(superblock, dentry->pathname, &size); if (d_file == NULL) + { return -ENOENT; + } rt_spin_lock(&superblock->lock); + d_file->nlink = 0; dfs_vfs_remove_node(&d_file->node); rt_spin_unlock(&superblock->lock); @@ -599,18 +709,11 @@ static int dfs_tmpfs_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *ne rt_size_t size; char *parent_path; char file_name[TMPFS_NAME_MAX]; + int ret; superblock = (struct tmpfs_sb *)old_dentry->mnt->data; RT_ASSERT(superblock != NULL); - d_file = dfs_tmpfs_lookup(superblock, new_dentry->pathname, &size); - if (d_file != NULL) - return -EEXIST; - - d_file = dfs_tmpfs_lookup(superblock, old_dentry->pathname, &size); - if (d_file == NULL) - return -ENOENT; - parent_path = rt_malloc(DFS_PATH_MAX); if (!parent_path) { @@ -618,21 +721,52 @@ static int dfs_tmpfs_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *ne } /* find parent file */ - _path_separate(new_dentry->pathname, parent_path, file_name); + ret = _path_separate(new_dentry->pathname, parent_path, DFS_PATH_MAX, + file_name, sizeof(file_name)); + if (ret != RT_EOK) + { + rt_free(parent_path); + return ret; + } if (file_name[0] == '\0') /* it's root dir */ { rt_free(parent_path); return -ENOENT; } + + d_file = dfs_tmpfs_lookup(superblock, new_dentry->pathname, &size); + if (d_file != NULL) + { + rt_free(parent_path); + return -EEXIST; + } + + d_file = dfs_tmpfs_lookup(superblock, old_dentry->pathname, &size); + if (d_file == NULL) + { + rt_free(parent_path); + return -ENOENT; + } + /* open parent directory */ p_file = dfs_tmpfs_lookup(superblock, parent_path, &size); - RT_ASSERT(p_file != NULL); + if (p_file == RT_NULL) + { + rt_free(parent_path); + return -ENOENT; + } + if (p_file->type != TMPFS_TYPE_DIR) + { + rt_free(parent_path); + return -ENOTDIR; + } rt_spin_lock(&superblock->lock); dfs_vfs_remove_node(&d_file->node); rt_spin_unlock(&superblock->lock); - strncpy(d_file->name, file_name, TMPFS_NAME_MAX); + rt_strncpy(d_file->name, file_name, sizeof(d_file->name)); + d_file->name[sizeof(d_file->name) - 1] = '\0'; rt_spin_lock(&superblock->lock); dfs_vfs_append_node(&p_file->node, &d_file->node); @@ -665,17 +799,17 @@ static struct dfs_vnode *_dfs_tmpfs_lookup(struct dfs_dentry *dentry) { if (d_file->type == TMPFS_TYPE_DIR) { - vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + vnode->mode = d_file->mode; vnode->type = FT_DIRECTORY; } else if (d_file->type == TMPFS_TYPE_SOCKET) { - vnode->mode = S_IFSOCK | (S_IRWXU | S_IRWXG | S_IRWXO); + vnode->mode = d_file->mode; vnode->type = FT_SOCKET; } else { - vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO); + vnode->mode = d_file->mode; vnode->type = FT_REGULAR; #ifdef RT_USING_PAGECACHE vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_tmp_aspace_ops); @@ -685,6 +819,7 @@ static struct dfs_vnode *_dfs_tmpfs_lookup(struct dfs_dentry *dentry) vnode->mnt = dentry->mnt; vnode->data = d_file; vnode->size = d_file->size; + vnode->nlink = d_file->nlink; } } @@ -699,6 +834,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t struct tmpfs_file *d_file, *p_file; char *parent_path; char file_name[TMPFS_NAME_MAX]; + int ret; if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL) { @@ -718,7 +854,15 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t if (vnode) { /* find parent file */ - _path_separate(dentry->pathname, parent_path, file_name); + ret = _path_separate(dentry->pathname, parent_path, DFS_PATH_MAX, + file_name, sizeof(file_name)); + if (ret != RT_EOK) + { + rt_set_errno(ret); + rt_free(parent_path); + dfs_vnode_destroy(vnode); + return RT_NULL; + } if (file_name[0] == '\0') /* it's root dir */ { rt_free(parent_path); @@ -746,30 +890,35 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t superblock->df_size += sizeof(struct tmpfs_file); - strncpy(d_file->name, file_name, TMPFS_NAME_MAX); + rt_strncpy(d_file->name, file_name, sizeof(d_file->name)); + d_file->name[sizeof(d_file->name) - 1] = '\0'; dfs_vfs_init_node(&d_file->node); d_file->data = NULL; d_file->size = 0; + d_file->nlink = 1; d_file->sb = superblock; d_file->fre_memory = RT_FALSE; if (type == FT_DIRECTORY) { d_file->type = TMPFS_TYPE_DIR; - vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + d_file->mode = S_IFDIR | (mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + vnode->mode = d_file->mode; vnode->type = FT_DIRECTORY; } else if (type == FT_SOCKET || (type == FT_REGULAR && S_ISSOCK(mode))) { d_file->type = TMPFS_TYPE_SOCKET; - vnode->mode = S_IFSOCK | (mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + d_file->mode = S_IFSOCK | (mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + vnode->mode = d_file->mode; vnode->type = FT_SOCKET; } else { d_file->type = TMPFS_TYPE_FILE; - vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO); + d_file->mode = S_IFREG | (mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + vnode->mode = d_file->mode; vnode->type = FT_REGULAR; #ifdef RT_USING_PAGECACHE vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_tmp_aspace_ops); @@ -782,6 +931,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t vnode->mnt = dentry->mnt; vnode->data = d_file; vnode->size = d_file->size; + vnode->nlink = d_file->nlink; } rt_free(parent_path); @@ -872,8 +1022,7 @@ static int dfs_tmpfs_truncate(struct dfs_file *file, off_t offset) return 0; } -static const struct dfs_file_ops _tmp_fops = -{ +static const struct dfs_file_ops _tmp_fops = { .open = dfs_tmpfs_open, .close = dfs_tmpfs_close, .ioctl = dfs_tmpfs_ioctl, @@ -884,8 +1033,7 @@ static const struct dfs_file_ops _tmp_fops = .truncate = dfs_tmpfs_truncate, }; -static const struct dfs_filesystem_ops _tmpfs_ops = -{ +static const struct dfs_filesystem_ops _tmpfs_ops = { .name = "tmp", .flags = DFS_FS_FLAG_DEFAULT, .default_fops = &_tmp_fops, @@ -896,14 +1044,14 @@ static const struct dfs_filesystem_ops _tmpfs_ops = .unlink = dfs_tmpfs_unlink, .stat = dfs_tmpfs_stat, + .setattr = dfs_tmpfs_setattr, .rename = dfs_tmpfs_rename, .lookup = _dfs_tmpfs_lookup, .create_vnode = dfs_tmpfs_create_vnode, .free_vnode = dfs_tmpfs_free_vnode }; -static struct dfs_filesystem_type _tmpfs = -{ +static struct dfs_filesystem_type _tmpfs = { .fs_ops = &_tmpfs_ops, }; diff --git a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h index 0807f06d19bc..ee3124f69e0d 100644 --- a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h +++ b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h @@ -14,8 +14,8 @@ #include #include -#define TMPFS_NAME_MAX 32 -#define TMPFS_MAGIC 0x0B0B0B0B +#define TMPFS_NAME_MAX DIRENT_NAME_MAX +#define TMPFS_MAGIC 0x0B0B0B0B #define TMPFS_TYPE_FILE 0x00 #define TMPFS_TYPE_DIR 0x01 @@ -25,22 +25,24 @@ struct tmpfs_sb; struct tmpfs_file { - rt_uint32_t type; /* file type */ + rt_uint32_t type; /* file type */ char name[TMPFS_NAME_MAX]; /* file name */ struct dfs_vfs_node node; /* file node in the tmpfs */ struct tmpfs_sb *sb; /* superblock ptr */ - rt_uint8_t *data; /* file date ptr */ - rt_size_t size; /* file size */ - rt_bool_t fre_memory;/* Whether to release memory upon close */ + rt_uint8_t *data; /* file date ptr */ + rt_size_t size; /* file size */ + rt_uint32_t nlink; /* hard link count */ + mode_t mode; /* file type and permission bits */ + rt_bool_t fre_memory;/* Whether to release memory upon close */ }; struct tmpfs_sb { - rt_uint32_t magic; /* TMPFS_MAGIC */ + rt_uint32_t magic; /* TMPFS_MAGIC */ struct tmpfs_file root; /* root dir */ - rt_size_t df_size; /* df size */ - rt_list_t sibling; /* sb sibling list */ + rt_size_t df_size; /* df size */ + rt_list_t sibling; /* sb sibling list */ struct rt_spinlock lock; /* tmpfs lock */ }; diff --git a/components/dfs/dfs_v2/filesystems/tmpfs/utest/tmpfs.c b/components/dfs/dfs_v2/filesystems/tmpfs/utest/tmpfs.c index 647944a71471..502c472718c8 100644 --- a/components/dfs/dfs_v2/filesystems/tmpfs/utest/tmpfs.c +++ b/components/dfs/dfs_v2/filesystems/tmpfs/utest/tmpfs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,7 @@ void run_copy() { int ret = 0; - ret = msh_exec("cd /tmp", 7); + ret = msh_exec("cd /tmp", 7); if (ret != 0) { LOG_E("errno=%d, ret=%d\n", errno, ret); @@ -56,17 +57,76 @@ void run_copy() } +static void run_long_name(void) +{ + static const char source[] = + "/tmp/iceoryx2_node_1234567890_abcdefghijklmnopqrstuvwxyz_shared"; + static const char destination[] = + "/tmp/iceoryx2_node_abcdefghijklmnopqrstuvwxyz_0987654321_renamed"; + static const char payload[] = "tmpfs-long-name"; + char buffer[sizeof(payload)] = { 0 }; + struct stat st = { 0 }; + int fd; + + fd = open(source, O_CREAT | O_RDWR | O_TRUNC, 0); + uassert_true(fd >= 0); + uassert_int_equal(fstat(fd, &st), 0); + uassert_int_equal(st.st_nlink, 1); + uassert_int_equal(write(fd, payload, sizeof(payload)), sizeof(payload)); + uassert_int_equal(close(fd), 0); + + uassert_int_equal(rename(source, destination), 0); + fd = open(destination, O_RDONLY, 0); + uassert_true(fd >= 0); + uassert_int_equal(read(fd, buffer, sizeof(buffer)), sizeof(buffer)); + uassert_str_equal(buffer, payload); + uassert_int_equal(close(fd), 0); + uassert_int_equal(unlink(destination), 0); +} -static void run_long_name_reject(void) +static void run_too_long_name_reject(void) { - static const char long_name[] = - "/tmp/abcdefghijklmnopqrstuvwxyz1234567890"; + static const char prefix[] = "/tmp/"; + char path[(sizeof(prefix) - 1) + DIRENT_NAME_MAX + 1]; int fd; - errno = 0; - fd = open(long_name, O_CREAT | O_RDWR, 0); + rt_memcpy(path, prefix, sizeof(prefix) - 1); + rt_memset(path + sizeof(prefix) - 1, 'x', DIRENT_NAME_MAX); + path[sizeof(path) - 1] = '\0'; + + fd = open(path, O_CREAT | O_RDWR, 0); uassert_int_equal(fd, -1); + + fd = open("/tmp/tmpfs-after-long-name", O_CREAT | O_RDWR | O_TRUNC, 0); + uassert_true(fd >= 0); + uassert_int_equal(close(fd), 0); + + errno = 0; + uassert_int_equal(rename("/tmp/tmpfs-after-long-name", path), -1); uassert_int_equal(errno, -ENAMETOOLONG); + uassert_int_equal(unlink("/tmp/tmpfs-after-long-name"), 0); +} + +static void run_mode_change(void) +{ + static const char path[] = "/tmp/tmpfs-mode-change"; + struct stat st = { 0 }; + int fd; + + unlink(path); + fd = open(path, O_CREAT | O_EXCL | O_RDWR, 0700); + uassert_true(fd >= 0); + uassert_int_equal(fstat(fd, &st), 0); + uassert_int_equal(st.st_mode & 0777, 0700); + uassert_int_equal(fchmod(fd, 0400), 0); + uassert_int_equal(fstat(fd, &st), 0); + uassert_int_equal(st.st_mode & 0777, 0400); + uassert_int_equal(close(fd), 0); + + errno = 0; + uassert_int_equal(open(path, O_WRONLY, 0), -1); + uassert_int_equal(errno, -EACCES); + uassert_int_equal(unlink(path), 0); } static rt_err_t utest_tc_init(void) @@ -81,6 +141,8 @@ static rt_err_t utest_tc_cleanup(void) static void testcase(void) { UTEST_UNIT_RUN(run_copy); - UTEST_UNIT_RUN(run_long_name_reject); + UTEST_UNIT_RUN(run_long_name); + UTEST_UNIT_RUN(run_too_long_name_reject); + UTEST_UNIT_RUN(run_mode_change); } UTEST_TC_EXPORT(testcase, "testcase.tfs.tmpfs", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/dfs/dfs_v2/include/dfs_file.h b/components/dfs/dfs_v2/include/dfs_file.h index 280d0dbcb9de..60401f7ef05b 100644 --- a/components/dfs/dfs_v2/include/dfs_file.h +++ b/components/dfs/dfs_v2/include/dfs_file.h @@ -163,9 +163,13 @@ off_t dfs_file_lseek(struct dfs_file *file, off_t offset, int wherece); int dfs_file_stat(const char *path, struct stat *buf); int dfs_file_lstat(const char *path, struct stat *buf); int dfs_file_setattr(const char *path, struct dfs_attr *attr); +int dfs_file_fsetattr(struct dfs_file *file, struct dfs_attr *attr); int dfs_file_fstat(struct dfs_file *file, struct stat *buf); int dfs_file_ioctl(struct dfs_file *file, int cmd, void *args); int dfs_file_fcntl(int fd, int cmd, unsigned long arg); +int dfs_record_lock_init(void); +int dfs_record_lock_fcntl(struct dfs_file *file, int cmd, struct flock *flock); +void dfs_record_lock_release(struct dfs_file *file, struct dfs_fdtable *owner); int dfs_file_fsync(struct dfs_file *file); int dfs_file_unlink(const char *path); int dfs_file_link(const char *oldname, const char *newname); diff --git a/components/dfs/dfs_v2/src/dfs.c b/components/dfs/dfs_v2/src/dfs.c index 92c688a8a070..f1601f000389 100644 --- a/components/dfs/dfs_v2/src/dfs.c +++ b/components/dfs/dfs_v2/src/dfs.c @@ -236,6 +236,7 @@ int dfs_init(void) /* create device filesystem lock */ rt_mutex_init(&fslock, "fslock", RT_IPC_FLAG_FIFO); rt_mutex_init(&fdlock, "fdlock", RT_IPC_FLAG_FIFO); + dfs_record_lock_init(); /* Initialize dentry system */ dfs_dentry_init(); @@ -740,6 +741,7 @@ int dfs_fdtable_dup(struct dfs_fdtable *fdt_dst, struct dfs_fdtable *fdt_src, in int dfs_fdtable_drop_fd(struct dfs_fdtable *fdt, int fd) { int err = 0; + struct dfs_file *file; if (fdt == NULL) { @@ -751,7 +753,15 @@ int dfs_fdtable_drop_fd(struct dfs_fdtable *fdt, int fd) return -RT_ENOSYS; } - err = dfs_file_close(fdt->fds[fd]); + file = fdt_get_file(fdt, fd); + if (file == RT_NULL) + { + dfs_file_unlock(); + return -EBADF; + } + + dfs_record_lock_release(file, fdt); + err = dfs_file_close(file); if (!err) { fdt_fd_release(fdt, fd); @@ -901,6 +911,7 @@ int dfs_dup_from(int oldfd, struct dfs_fdtable *fdtab) file->data = fdtab->fds[oldfd]->data; } + dfs_record_lock_release(fdtab->fds[oldfd], fdtab); dfs_file_close(fdtab->fds[oldfd]); exit: @@ -990,6 +1001,7 @@ rt_err_t sys_dup2(int oldfd, int newfd) if (fdt->fds[newfd]) { + dfs_record_lock_release(fdt->fds[newfd], fdt); ret = dfs_file_close(fdt->fds[newfd]); if (ret < 0) { diff --git a/components/dfs/dfs_v2/src/dfs_file.c b/components/dfs/dfs_v2/src/dfs_file.c index 6b1615939677..970b74c6caee 100644 --- a/components/dfs/dfs_v2/src/dfs_file.c +++ b/components/dfs/dfs_v2/src/dfs_file.c @@ -558,7 +558,7 @@ char *dfs_file_realpath(struct dfs_mnt **mnt, const char *fullpath, int mode) * @return 0 on successful, -1 on failure: * -ENOENT if file doesn't exist and O_CREAT not set * -EEXIST if file exists and O_EXCL|O_CREAT set - * -EPERM if permission denied + * -EACCES if permission denied * -ENOTDIR if path is not a directory when O_DIRECTORY set * -EISDIR if path is directory when opening as regular file */ @@ -763,7 +763,7 @@ int dfs_file_open(struct dfs_file *file, const char *path, int oflags, mode_t mo { DLOG(msg, "dfs_file", mnt->fs_ops->name, DLOG_MSG, "no permission or fops->open"); dfs_file_unref(file); - ret = -EPERM; + ret = -EACCES; } } else @@ -1401,6 +1401,10 @@ int dfs_file_stat(const char *path, struct stat *buf) if (dfs_is_mounted(mnt) == 0) { ret = mnt->fs_ops->stat(dentry, buf); + if (ret == RT_EOK && buf->st_nlink == 0 && dentry->vnode != RT_NULL) + { + buf->st_nlink = dentry->vnode->nlink; + } } } @@ -1470,6 +1474,10 @@ int dfs_file_lstat(const char *path, struct stat *buf) if (dfs_is_mounted(mnt) == 0) { ret = mnt->fs_ops->stat(dentry, buf); + if (ret == RT_EOK && buf->st_nlink == 0 && dentry->vnode != RT_NULL) + { + buf->st_nlink = dentry->vnode->nlink; + } } } @@ -1596,6 +1604,29 @@ int dfs_file_setattr(const char *path, struct dfs_attr *attr) return ret; } +int dfs_file_fsetattr(struct dfs_file *file, struct dfs_attr *attr) +{ + struct dfs_mnt *mnt; + + if (file == RT_NULL || file->dentry == RT_NULL || attr == RT_NULL) + { + return -EBADF; + } + + mnt = file->dentry->mnt; + if (mnt == RT_NULL || mnt->fs_ops == RT_NULL || + mnt->fs_ops->setattr == RT_NULL) + { + return -ENOSYS; + } + if (dfs_is_mounted(mnt) != 0) + { + return -EINVAL; + } + + return mnt->fs_ops->setattr(file->dentry, attr); +} + /** * @brief Perform device-specific control operations * @@ -1654,7 +1685,7 @@ int dfs_file_ioctl(struct dfs_file *file, int cmd, void *args) * - F_SETFD: Set file descriptor flags * - F_GETFL: Get file status flags * - F_SETFL: Set file status flags - * - F_GETLK/F_SETLK/F_SETLKW: File locking operations (unimplemented) + * - F_GETLK/F_SETLK/F_SETLKW: POSIX advisory record locking * - F_DUPFD_CLOEXEC: Duplicate file descriptor with close-on-exec flag (if supported) * * @param[in] fd File descriptor to operate on @@ -1670,7 +1701,6 @@ int dfs_file_ioctl(struct dfs_file *file, int cmd, void *args) * -EPERM for unsupported commands * * @note Not all commands may be supported by all filesystems - * @note File locking operations (F_GETLK/F_SETLK/F_SETLKW) are currently unimplemented */ int dfs_file_fcntl(int fd, int cmd, unsigned long arg) { @@ -1724,9 +1754,11 @@ int dfs_file_fcntl(int fd, int cmd, unsigned long arg) break; } case F_GETLK: + ret = dfs_record_lock_fcntl(file, cmd, (struct flock *)arg); break; case F_SETLK: case F_SETLKW: + ret = dfs_record_lock_fcntl(file, cmd, (struct flock *)arg); break; #ifdef RT_USING_MUSLLIBC case F_DUPFD_CLOEXEC: diff --git a/components/dfs/dfs_v2/src/dfs_posix.c b/components/dfs/dfs_v2/src/dfs_posix.c index 2ca7b66f7e82..77410c4dd55e 100644 --- a/components/dfs/dfs_v2/src/dfs_posix.c +++ b/components/dfs/dfs_v2/src/dfs_posix.c @@ -119,7 +119,7 @@ int openat(int dirfd, const char *path, int flag, ...) return -1; } - fullpath = (char*)path; + fullpath = (char *)path; if (path[0] != '/') { @@ -176,7 +176,7 @@ int utimensat(int __fd, const char *__path, const struct timespec __times[2], in } else { - fullpath = (char*)__path; + fullpath = (char *)__path; } } else @@ -291,17 +291,8 @@ RTM_EXPORT(creat); int close(int fd) { int result; - struct dfs_file *file; - - file = fd_get(fd); - if (file == NULL) - { - rt_set_errno(-EBADF); - - return -1; - } - result = dfs_file_close(file); + result = dfs_fdtable_drop_fd(dfs_fdtable_get(), fd); if (result < 0) { rt_set_errno(result); @@ -309,8 +300,6 @@ int close(int fd) return -1; } - fd_release(fd); - return 0; } RTM_EXPORT(close); @@ -335,17 +324,22 @@ ssize_t read(int fd, void *buf, size_t len) ssize_t result; struct dfs_file *file; - if (buf == NULL) + file = fd_get(fd); + if (file == NULL) { rt_set_errno(-EBADF); + return -1; } - file = fd_get(fd); - if (file == NULL) + if (len == 0) { - rt_set_errno(-EBADF); + return 0; + } + if (buf == NULL) + { + rt_set_errno(-EBADF); return -1; } @@ -380,17 +374,22 @@ ssize_t write(int fd, const void *buf, size_t len) ssize_t result; struct dfs_file *file; - if (buf == NULL) + file = fd_get(fd); + if (file == NULL) { rt_set_errno(-EBADF); + return -1; } - file = fd_get(fd); - if (file == NULL) + if (len == 0) { - rt_set_errno(-EBADF); + return 0; + } + if (buf == NULL) + { + rt_set_errno(-EBADF); return -1; } @@ -581,6 +580,10 @@ int fstat(int fildes, struct stat *buf) if (dfs_is_mounted(file->dentry->mnt) == 0) { ret = file->dentry->mnt->fs_ops->stat(file->dentry, buf); + if (ret == RT_EOK && buf->st_nlink == 0 && file->vnode != RT_NULL) + { + buf->st_nlink = file->vnode->nlink; + } } return ret; @@ -655,11 +658,18 @@ int fcntl(int fildes, int cmd, ...) arg = va_arg(ap, void *); va_end(ap); - ret = dfs_file_ioctl(file, cmd, arg); - if (ret < 0) + if (cmd == F_GETLK || cmd == F_SETLK || cmd == F_SETLKW) { ret = dfs_file_fcntl(fildes, cmd, (unsigned long)arg); } + else + { + ret = dfs_file_ioctl(file, cmd, arg); + if (ret < 0) + { + ret = dfs_file_fcntl(fildes, cmd, (unsigned long)arg); + } + } } else { @@ -676,6 +686,32 @@ int fcntl(int fildes, int cmd, ...) } RTM_EXPORT(fcntl); +int fchmod(int fildes, mode_t mode) +{ + int ret; + struct dfs_attr attr = { 0 }; + struct dfs_file *file; + + file = fd_get(fildes); + if (file == RT_NULL) + { + rt_set_errno(-EBADF); + return -1; + } + + attr.st_mode = mode; + attr.ia_valid = ATTR_MODE_SET; + ret = dfs_file_fsetattr(file, &attr); + if (ret < 0) + { + rt_set_errno(ret); + return -1; + } + + return 0; +} +RTM_EXPORT(fchmod); + /** * this function is a POSIX compliant version, which shall perform a variety of * control functions on devices. @@ -892,7 +928,9 @@ int rmdir(const char *pathname) { dirent = readdir(dir); if (dirent == RT_NULL) + { break; + } if (rt_strcmp(".", dirent->d_name) != 0 && rt_strcmp("..", dirent->d_name) != 0) { @@ -964,7 +1002,7 @@ DIR *opendir(const char *name) if (result >= 0) { /* open successfully */ - t = (DIR *) rt_malloc(sizeof(DIR)); + t = (DIR *)rt_malloc(sizeof(DIR)); if (t == NULL) { dfs_file_close(file); @@ -1109,10 +1147,12 @@ void seekdir(DIR *d, long offset) { /* seek to the offset position of directory */ if (dfs_file_lseek(fd_get(d->fd), 0, SEEK_SET) >= 0) + { d->num = d->cur = 0; + } } - while(file->fpos < offset) + while (file->fpos < offset) { if (!readdir(d)) { @@ -1135,7 +1175,9 @@ void rewinddir(DIR *d) { /* seek to the beginning of directory */ if (dfs_file_lseek(fd_get(d->fd), 0, SEEK_SET) >= 0) + { d->num = d->cur = 0; + } } } RTM_EXPORT(rewinddir); @@ -1335,7 +1377,7 @@ void setcwd(char *buf) rt_kprintf(NO_WORKING_DIR); #endif - return ; + return; } RTM_EXPORT(setcwd); diff --git a/components/dfs/dfs_v2/src/dfs_record_lock.c b/components/dfs/dfs_v2/src/dfs_record_lock.c new file mode 100644 index 000000000000..1d159c025736 --- /dev/null +++ b/components/dfs/dfs_v2/src/dfs_record_lock.c @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2006-2026 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#ifdef RT_USING_SMART +#include +#endif + +struct dfs_lock_range +{ + off_t start; + off_t end; + rt_bool_t to_eof; +}; + +struct dfs_record_lock +{ + rt_list_t list; + struct dfs_vnode *vnode; + struct dfs_fdtable *owner; + pid_t pid; + short type; + struct dfs_lock_range range; +}; + +static rt_list_t _record_locks; +static struct rt_semaphore _record_lock_changed; +static int _record_lock_waiters; + +static off_t _off_max(void) +{ + return sizeof(off_t) == sizeof(rt_int64_t) ? (off_t)INT64_MAX : (off_t)INT32_MAX; +} + +static off_t _off_min(void) +{ + off_t max = _off_max(); + + return -max - 1; +} + +static int _add_offset(off_t left, off_t right, off_t *result) +{ + off_t max = _off_max(); + off_t min = _off_min(); + + if ((right > 0 && left > max - right) || + (right < 0 && left < min - right)) + { + return -EOVERFLOW; + } + + *result = left + right; + return 0; +} + +static int _normalize_range(struct dfs_file *file, const struct flock *flock, + struct dfs_lock_range *range) +{ + off_t base; + off_t origin; + off_t end; + int ret; + + switch (flock->l_whence) + { + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = dfs_file_get_fpos(file); + break; + case SEEK_END: + if (file->vnode->size > (size_t)_off_max()) + { + return -EOVERFLOW; + } + base = (off_t)file->vnode->size; + break; + default: + return -EINVAL; + } + + ret = _add_offset(base, flock->l_start, &origin); + if (ret < 0 || origin < 0) + { + return ret < 0 ? ret : -EINVAL; + } + + range->to_eof = RT_FALSE; + if (flock->l_len == 0) + { + range->start = origin; + range->end = 0; + range->to_eof = RT_TRUE; + return 0; + } + + if (flock->l_len > 0) + { + ret = _add_offset(origin, flock->l_len - 1, &end); + if (ret < 0) + { + return ret; + } + range->start = origin; + range->end = end; + } + else + { + ret = _add_offset(origin, flock->l_len, &range->start); + if (ret < 0 || range->start < 0 || origin == 0) + { + return ret < 0 ? ret : -EINVAL; + } + range->end = origin - 1; + } + + if (range->end == _off_max()) + { + range->end = 0; + range->to_eof = RT_TRUE; + } + return 0; +} + +static rt_bool_t _ranges_overlap(const struct dfs_lock_range *left, + const struct dfs_lock_range *right) +{ + if (!left->to_eof && left->end < right->start) + { + return RT_FALSE; + } + if (!right->to_eof && right->end < left->start) + { + return RT_FALSE; + } + return RT_TRUE; +} + +static rt_bool_t _ranges_touch(const struct dfs_lock_range *left, + const struct dfs_lock_range *right) +{ + if (_ranges_overlap(left, right)) + { + return RT_TRUE; + } + if (!left->to_eof && left->end < _off_max() && + left->end + 1 == right->start) + { + return RT_TRUE; + } + if (!right->to_eof && right->end < _off_max() && + right->end + 1 == left->start) + { + return RT_TRUE; + } + return RT_FALSE; +} + +static rt_bool_t _locks_conflict(short requested_type, + const struct dfs_record_lock *lock, + const struct dfs_lock_range *range, + struct dfs_fdtable *owner) +{ + if (lock->owner == owner || !_ranges_overlap(&lock->range, range)) + { + return RT_FALSE; + } + return requested_type == F_WRLCK || lock->type == F_WRLCK; +} + +static struct dfs_record_lock *_find_conflict( + struct dfs_vnode *vnode, struct dfs_fdtable *owner, short type, + const struct dfs_lock_range *range) +{ + rt_list_t *node; + struct dfs_record_lock *result = RT_NULL; + + rt_list_for_each(node, &_record_locks) + { + struct dfs_record_lock *lock; + + lock = rt_list_entry(node, struct dfs_record_lock, list); + if (lock->vnode == vnode && + _locks_conflict(type, lock, range, owner) && + (result == RT_NULL || lock->range.start < result->range.start)) + { + result = lock; + } + } + return result; +} + +static struct dfs_record_lock *_split_lock_needed( + struct dfs_vnode *vnode, struct dfs_fdtable *owner, + const struct dfs_lock_range *range) +{ + rt_list_t *node; + + if (range->to_eof) + { + return RT_NULL; + } + + rt_list_for_each(node, &_record_locks) + { + struct dfs_record_lock *lock; + + lock = rt_list_entry(node, struct dfs_record_lock, list); + if (lock->vnode == vnode && lock->owner == owner && + lock->range.start < range->start && + (lock->range.to_eof || lock->range.end > range->end)) + { + return lock; + } + } + return RT_NULL; +} + +static int _remove_owner_range(struct dfs_vnode *vnode, + struct dfs_fdtable *owner, + const struct dfs_lock_range *range) +{ + struct dfs_record_lock *split_source; + struct dfs_record_lock *split = RT_NULL; + rt_list_t *node; + rt_list_t *next; + + split_source = _split_lock_needed(vnode, owner, range); + if (split_source != RT_NULL) + { + split = rt_malloc(sizeof(*split)); + if (split == RT_NULL) + { + return -ENOLCK; + } + *split = *split_source; + rt_list_init(&split->list); + split->range.start = range->end + 1; + rt_list_insert_after(&split_source->list, &split->list); + } + + rt_list_for_each_safe(node, next, &_record_locks) + { + struct dfs_record_lock *lock; + + lock = rt_list_entry(node, struct dfs_record_lock, list); + if (lock == split || lock->vnode != vnode || lock->owner != owner || + !_ranges_overlap(&lock->range, range)) + { + continue; + } + + if (lock->range.start < range->start) + { + lock->range.end = range->start - 1; + lock->range.to_eof = RT_FALSE; + } + else if (!range->to_eof && + (lock->range.to_eof || lock->range.end > range->end)) + { + lock->range.start = range->end + 1; + } + else + { + rt_list_remove(&lock->list); + rt_free(lock); + } + } + return 0; +} + +static void _merge_owner_locks(struct dfs_record_lock *target) +{ + rt_list_t *node; + rt_list_t *next; + rt_bool_t merged; + + do + { + merged = RT_FALSE; + rt_list_for_each_safe(node, next, &_record_locks) + { + struct dfs_record_lock *lock; + + lock = rt_list_entry(node, struct dfs_record_lock, list); + if (lock == target || lock->vnode != target->vnode || + lock->owner != target->owner || lock->type != target->type || + !_ranges_touch(&lock->range, &target->range)) + { + continue; + } + + if (lock->range.start < target->range.start) + { + target->range.start = lock->range.start; + } + if (lock->range.to_eof || target->range.to_eof) + { + target->range.to_eof = RT_TRUE; + target->range.end = 0; + } + else if (lock->range.end > target->range.end) + { + target->range.end = lock->range.end; + } + rt_list_remove(&lock->list); + rt_free(lock); + merged = RT_TRUE; + } + } while (merged); +} + +static void _wake_waiter(void) +{ + if (_record_lock_waiters > 0) + { + rt_sem_release(&_record_lock_changed); + } +} + +static pid_t _owner_pid(struct dfs_fdtable *owner) +{ +#ifdef RT_USING_SMART + if (owner != RT_NULL && owner != dfs_fdtable_get_global()) + { + struct rt_lwp *lwp; + + lwp = rt_container_of(owner, struct rt_lwp, fdt); + return lwp->pid; + } +#endif + return 0; +} + +static int _set_lock(struct dfs_file *file, int cmd, struct flock *flock, + const struct dfs_lock_range *range) +{ + struct dfs_fdtable *owner = dfs_fdtable_get(); + struct dfs_record_lock *new_lock = RT_NULL; + rt_bool_t waiting = RT_FALSE; + int ret; + + if (flock->l_type != F_UNLCK) + { + new_lock = rt_malloc(sizeof(*new_lock)); + if (new_lock == RT_NULL) + { + return -ENOLCK; + } + new_lock->vnode = file->vnode; + new_lock->owner = owner; + new_lock->pid = _owner_pid(owner); + new_lock->type = flock->l_type; + new_lock->range = *range; + rt_list_init(&new_lock->list); + } + + for (;;) + { + if (dfs_file_lock() != RT_EOK) + { + ret = -ENOSYS; + break; + } + + if (flock->l_type != F_UNLCK && + _find_conflict(file->vnode, owner, flock->l_type, range) != RT_NULL) + { + if (cmd == F_SETLK) + { + dfs_file_unlock(); + ret = -EAGAIN; + break; + } + if (!waiting) + { + _record_lock_waiters++; + waiting = RT_TRUE; + } + dfs_file_unlock(); + if (rt_sem_take_interruptible(&_record_lock_changed, + RT_WAITING_FOREVER) != RT_EOK) + { + ret = -EINTR; + break; + } + continue; + } + + ret = _remove_owner_range(file->vnode, owner, range); + if (ret == 0 && new_lock != RT_NULL) + { + rt_list_insert_before(&_record_locks, &new_lock->list); + _merge_owner_locks(new_lock); + new_lock = RT_NULL; + } + if (waiting) + { + _record_lock_waiters--; + waiting = RT_FALSE; + } + if (ret == 0) + { + _wake_waiter(); + } + dfs_file_unlock(); + break; + } + + if (waiting && dfs_file_lock() == RT_EOK) + { + _record_lock_waiters--; + dfs_file_unlock(); + } + if (new_lock != RT_NULL) + { + rt_free(new_lock); + } + return ret; +} + +int dfs_record_lock_init(void) +{ + rt_list_init(&_record_locks); + _record_lock_waiters = 0; + return rt_sem_init(&_record_lock_changed, "freclck", 0, + RT_IPC_FLAG_FIFO); +} + +int dfs_record_lock_fcntl(struct dfs_file *file, int cmd, struct flock *flock) +{ + struct dfs_lock_range range; + struct dfs_record_lock *conflict; + struct dfs_fdtable *owner; + int access; + int ret; + + if (file == RT_NULL || file->vnode == RT_NULL || flock == RT_NULL) + { + return -EBADF; + } + if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK && + (flock->l_type != F_UNLCK || cmd == F_GETLK)) + { + return -EINVAL; + } + + access = dfs_fflags(file->flags); + if ((flock->l_type == F_RDLCK && !(access & DFS_F_FREAD)) || + (flock->l_type == F_WRLCK && !(access & DFS_F_FWRITE))) + { + return -EBADF; + } + + ret = _normalize_range(file, flock, &range); + if (ret < 0) + { + return ret; + } + if (cmd != F_GETLK) + { + return _set_lock(file, cmd, flock, &range); + } + + owner = dfs_fdtable_get(); + if (dfs_file_lock() != RT_EOK) + { + return -ENOSYS; + } + conflict = _find_conflict(file->vnode, owner, flock->l_type, &range); + if (conflict == RT_NULL) + { + flock->l_type = F_UNLCK; + } + else + { + flock->l_type = conflict->type; + flock->l_whence = SEEK_SET; + flock->l_start = conflict->range.start; + flock->l_len = conflict->range.to_eof ? 0 : conflict->range.end - conflict->range.start + 1; + flock->l_pid = conflict->pid; + } + dfs_file_unlock(); + return 0; +} + +void dfs_record_lock_release(struct dfs_file *file, struct dfs_fdtable *owner) +{ + rt_list_t *node; + rt_list_t *next; + rt_bool_t changed = RT_FALSE; + + if (file == RT_NULL || file->vnode == RT_NULL || owner == RT_NULL || + dfs_file_lock() != RT_EOK) + { + return; + } + + rt_list_for_each_safe(node, next, &_record_locks) + { + struct dfs_record_lock *lock; + + lock = rt_list_entry(node, struct dfs_record_lock, list); + if (lock->vnode == file->vnode && lock->owner == owner) + { + rt_list_remove(&lock->list); + rt_free(lock); + changed = RT_TRUE; + } + } + if (changed) + { + _wake_waiter(); + } + dfs_file_unlock(); +} diff --git a/components/dfs/dfs_v2/src/dfs_vnode.c b/components/dfs/dfs_v2/src/dfs_vnode.c index 462f94e05e68..0b133c1d2395 100644 --- a/components/dfs/dfs_v2/src/dfs_vnode.c +++ b/components/dfs/dfs_v2/src/dfs_vnode.c @@ -36,6 +36,7 @@ int dfs_vnode_init(struct dfs_vnode *vnode, int type, const struct dfs_file_ops vnode->type = type; rt_atomic_store(&(vnode->ref_count), 1); + vnode->nlink = 1; vnode->mnt = RT_NULL; vnode->fops = fops; } @@ -58,6 +59,7 @@ struct dfs_vnode *dfs_vnode_create(void) } rt_atomic_store(&(vnode->ref_count), 1); + vnode->nlink = 1; LOG_I("create a vnode: %p", vnode); diff --git a/components/drivers/virtio/Kconfig b/components/drivers/virtio/Kconfig index afa92546f388..37ed49d8767f 100644 --- a/components/drivers/virtio/Kconfig +++ b/components/drivers/virtio/Kconfig @@ -21,7 +21,7 @@ config RT_VIRTIO_TRANSPORT_PCI config RT_VIRTIO_NET bool "VirtIO Net" depends on RT_USING_VIRTIO - depends on RT_USING_ETHERNET + depends on RT_USING_LWIP default y config RT_VIRTIO_BLK diff --git a/components/libc/Kconfig b/components/libc/Kconfig index f25104d8af62..c30f67d73b2e 100644 --- a/components/libc/Kconfig +++ b/components/libc/Kconfig @@ -1,5 +1,17 @@ menu "C/C++ and POSIX layer" +config RT_USING_LIBC + bool "Enable libc" + default y if RT_USING_SMART + default n + +config RT_USING_MUSLLIBC + bool "Enable musl libc" + depends on RT_USING_SMART + depends on RT_USING_LIBC + default y if RT_USING_SMART + default n + config RT_USING_EXTERNAL_LIBC bool help diff --git a/components/libc/compilers/musl/SConscript b/components/libc/compilers/musl/SConscript index 2b152cb38ae9..af6e0bfd5134 100644 --- a/components/libc/compilers/musl/SConscript +++ b/components/libc/compilers/musl/SConscript @@ -7,17 +7,16 @@ group = [] musllibc_version = GetMuslVersion(rtconfig) -if musllibc_version: +if musllibc_version and GetDepend('RT_USING_MUSLLIBC'): print('Musl version: ' + musllibc_version) cwd = GetCurrentDir() src = Glob('*.c') CPPPATH = [cwd] - CPPDEFINES = ['RT_USING_MUSLLIBC', 'RT_USING_LIBC'] + CPPDEFINES = [] LIBS = ['c', 'gcc'] LINKFLAGS = ' --specs=kernel.specs' - AddDepend(['RT_USING_MUSLLIBC', 'RT_USING_LIBC']) group = group + DefineGroup('Libc', src, depend = [''], CPPPATH = CPPPATH, LINKFLAGS = LINKFLAGS, CPPDEFINES = CPPDEFINES, LIBS = LIBS) diff --git a/components/libc/posix/io/epoll/epoll.c b/components/libc/posix/io/epoll/epoll.c index a4c9dcfc0628..9aa11e2d87fb 100644 --- a/components/libc/posix/io/epoll/epoll.c +++ b/components/libc/posix/io/epoll/epoll.c @@ -31,6 +31,15 @@ EPOLLET | EPOLLEXCLUSIVE) struct rt_eventpoll; +struct rt_fd_list; + +struct rt_epoll_waiter +{ + struct rt_wqueue_node wqn; + struct rt_fd_list *fdlist; + struct rt_epoll_waiter *next; + rt_bool_t queued; +}; enum rt_epoll_status { RT_EPOLL_STAT_INIT, @@ -45,7 +54,7 @@ struct rt_fd_list struct epoll_event epev; /**< Epoll event structure */ rt_pollreq_t req; /**< Poll request structure */ struct rt_eventpoll *ep; /**< Pointer to the associated event poll */ - struct rt_wqueue_node wqn; /**< Wait queue node */ + struct rt_epoll_waiter *waiters; /**< Wait nodes registered by poll */ int exclusive; /**< Indicates if the event is exclusive */ rt_bool_t is_rdl_node; /**< Indicates if the node is in the ready list */ int fd; /**< File descriptor */ @@ -71,6 +80,42 @@ static int epoll_poll(struct dfs_file *file, struct rt_pollreq *req); static int epoll_get_event(struct rt_fd_list *fl, rt_pollreq_t *req); static int epoll_do_ctl(int epfd, int op, int fd, struct epoll_event *event); +static void epoll_remove_waiters(struct rt_fd_list *fdlist) +{ + struct rt_epoll_waiter *waiter; + + while (fdlist->waiters != RT_NULL) + { + waiter = fdlist->waiters; + fdlist->waiters = waiter->next; + if (waiter->queued) + { + rt_wqueue_remove(&waiter->wqn); + waiter->queued = RT_FALSE; + } + rt_free(waiter); + } +} + +static void epoll_set_polling_thread(struct rt_eventpoll *ep, + rt_thread_t thread) +{ + struct rt_epoll_waiter *waiter; + struct rt_fd_list *fdlist; + + rt_mutex_take(&ep->lock, RT_WAITING_FOREVER); + ep->polling_thread = thread; + for (fdlist = ep->fdlist; fdlist != RT_NULL; fdlist = fdlist->next) + { + for (waiter = fdlist->waiters; waiter != RT_NULL; + waiter = waiter->next) + { + waiter->wqn.polling_thread = thread; + } + } + rt_mutex_release(&ep->lock); +} + static const struct dfs_file_ops epoll_fops = { .close = epoll_close, @@ -96,7 +141,7 @@ static int epoll_close_fdlist(struct rt_fd_list *fdlist) while (list->next != RT_NULL) { fre_node = list->next; - rt_wqueue_remove(&fre_node->wqn); + epoll_remove_waiters(fre_node); list->next = fre_node->next; rt_free(fre_node); @@ -196,6 +241,7 @@ static int epoll_poll(struct dfs_file *file, struct rt_pollreq *req) static int epoll_wqueue_callback(struct rt_wqueue_node *wait, void *key) { struct rt_fd_list *fdlist; + struct rt_epoll_waiter *waiter; struct rt_eventpoll *ep; rt_base_t level; int is_waiting = 0; @@ -203,7 +249,8 @@ static int epoll_wqueue_callback(struct rt_wqueue_node *wait, void *key) if (key && !((rt_ubase_t)key & wait->key)) return -1; - fdlist = rt_container_of(wait, struct rt_fd_list, wqn); + waiter = rt_container_of(wait, struct rt_epoll_waiter, wqn); + fdlist = waiter->fdlist; ep = fdlist->ep; if (ep) @@ -242,17 +289,34 @@ static void epoll_wqueue_add_callback(rt_wqueue_t *wq, rt_pollreq_t *req) { struct rt_fd_list *fdlist; struct rt_eventpoll *ep; + struct rt_epoll_waiter *waiter; fdlist = rt_container_of(req, struct rt_fd_list, req); ep = fdlist->ep; - fdlist->wqn.key = req->_key; - - rt_list_init(&(fdlist->wqn.list)); + for (waiter = fdlist->waiters; waiter != RT_NULL; waiter = waiter->next) + { + if (waiter->wqn.wqueue == wq) + { + waiter->wqn.key |= req->_key; + return; + } + } - fdlist->wqn.polling_thread = ep->polling_thread; - fdlist->wqn.wakeup = epoll_wqueue_callback; - rt_wqueue_add(wq, &fdlist->wqn); + waiter = (struct rt_epoll_waiter *)rt_calloc(1, sizeof(*waiter)); + if (waiter == RT_NULL) + { + return; + } + waiter->fdlist = fdlist; + waiter->wqn.key = req->_key; + waiter->wqn.polling_thread = ep->polling_thread; + waiter->wqn.wakeup = epoll_wqueue_callback; + rt_list_init(&waiter->wqn.list); + waiter->next = fdlist->waiters; + fdlist->waiters = waiter; + rt_wqueue_add(wq, &waiter->wqn); + waiter->queued = RT_TRUE; } /** @@ -346,6 +410,7 @@ static int epoll_epf_init(int fd) ep->fdlist->next = RT_NULL; ep->fdlist->fd = fd; ep->fdlist->ep = ep; + ep->fdlist->waiters = RT_NULL; ep->fdlist->exclusive = 0; ep->fdlist->is_rdl_node = RT_FALSE; dfs_vnode_init(df->vnode, FT_REGULAR, &epoll_fops); @@ -457,6 +522,7 @@ static int epoll_ctl_add(struct dfs_file *df, int fd, struct epoll_event *event) memcpy(&fdlist->epev.data, &event->data, sizeof(event->data)); fdlist->epev.events = 0; fdlist->ep = ep; + fdlist->waiters = RT_NULL; fdlist->exclusive = 0; fdlist->is_rdl_node = RT_FALSE; fdlist->req._proc = epoll_wqueue_add_callback; @@ -520,8 +586,7 @@ static int epoll_ctl_del(struct dfs_file *df, int fd) fre_fd = fdlist->next; fdlist->next = fdlist->next->next; - if (fre_fd->wqn.wqueue) - rt_wqueue_remove(&fre_fd->wqn); + epoll_remove_waiters(fre_fd); rt_free(fre_fd); break; @@ -570,8 +635,7 @@ static int epoll_ctl_mod(struct dfs_file *df, int fd, struct epoll_event *event) rt_mutex_take(&ep->lock, RT_WAITING_FOREVER); memcpy(&fdlist->next->epev.data, &event->data, sizeof(event->data)); fdlist->next->revents = event->events; - if (fdlist->next->wqn.wqueue) - rt_wqueue_remove(&fdlist->next->wqn); + epoll_remove_waiters(fdlist->next); rt_mutex_release(&ep->lock); epoll_ctl_install(fdlist->next, ep); @@ -804,10 +868,7 @@ static int epoll_do(struct rt_eventpoll *ep, struct epoll_event *events, int max isn_add = 0; if (event_num < maxevents) { - if (rdlist->wqn.wqueue) - { - rt_wqueue_remove(&rdlist->wqn); - } + epoll_remove_waiters(rdlist); mask = epoll_get_event(rdlist, &rdlist->req); @@ -825,8 +886,7 @@ static int epoll_do(struct rt_eventpoll *ep, struct epoll_event *events, int max { rdlist->revents = 0; isfree = 1; - if (rdlist->wqn.wqueue) - rt_wqueue_remove(&rdlist->wqn); + epoll_remove_waiters(rdlist); } else { @@ -864,7 +924,7 @@ static int epoll_do(struct rt_eventpoll *ep, struct epoll_event *events, int max else { level = rt_spin_lock_irqsave(&ep->spinlock); - if (!rdlist->wqn.wqueue) + if (rdlist->waiters == RT_NULL) { epoll_get_event(rdlist, &rdlist->req); } @@ -937,6 +997,7 @@ static int epoll_do_wait(int epfd, struct epoll_event *events, int maxevents, in ep = (struct rt_eventpoll *)df->vnode->data; if (ep) { + epoll_set_polling_thread(ep, rt_thread_self()); ret = epoll_do(ep, events, maxevents, timeout); } } @@ -1039,4 +1100,3 @@ int epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, int timeou { return epoll_do_wait(epfd, events, maxevents, timeout, ss); } - diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c index 82f205a694e0..12a4dde86f0a 100644 --- a/components/lwp/lwp_pid.c +++ b/components/lwp/lwp_pid.c @@ -413,8 +413,7 @@ static void __exit_files(struct rt_lwp *lwp) d = lwp->fdt.fds[fd]; if (d) { - dfs_file_close(d); - fdt_fd_release(&lwp->fdt, fd); + dfs_fdtable_drop_fd(&lwp->fdt, fd); } fd--; } diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index ea096f2a906c..a871f71b513e 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -425,20 +425,18 @@ ssize_t sys_read(int fd, void *buf, size_t nbyte) void *kmem = RT_NULL; ssize_t ret = -1; - if (!nbyte) - { - return -EINVAL; - } - - if (!lwp_user_accessable((void *)buf, nbyte)) + if (nbyte) { - return -EFAULT; - } + if (!lwp_user_accessable((void *)buf, nbyte)) + { + return -EFAULT; + } - kmem = kmem_get(nbyte); - if (!kmem) - { - return -ENOMEM; + kmem = kmem_get(nbyte); + if (!kmem) + { + return -ENOMEM; + } } ret = read(fd, kmem, nbyte); @@ -794,6 +792,28 @@ sysret_t sys_close(int fd) */ sysret_t sys_ioctl(int fd, unsigned long cmd, void *data) { +#ifdef ARCH_MM_MMU + if (cmd == F_GETLK || cmd == F_SETLK || cmd == F_SETLKW) + { + struct flock lock; + int ret; + + if (data == RT_NULL || + !lwp_user_accessable(data, sizeof(lock)) || + lwp_get_from_user(&lock, data, sizeof(lock)) != sizeof(lock)) + { + return -EFAULT; + } + + ret = ioctl(fd, cmd, &lock); + if (ret >= 0 && cmd == F_GETLK && + lwp_put_to_user(data, &lock, sizeof(lock)) != sizeof(lock)) + { + return -EFAULT; + } + return ret < 0 ? GET_ERRNO() : ret; + } +#endif int ret = ioctl(fd, cmd, data); return (ret < 0 ? GET_ERRNO() : ret); } @@ -5680,7 +5700,9 @@ static void cmsg_level_lwip_2_muslc(struct msghdr *message) static int copy_msghdr_from_user(struct msghdr *kmsg, struct musl_msghdr *umsg, struct iovec **out_iov, void **out_msg_control, - void **out_msg_name, void **out_buffer) + void **out_msg_name, void **out_buffer, + socklen_t *out_user_name_length, + rt_bool_t receive) { int index; size_t iovs_size; @@ -5704,12 +5726,33 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, kmsg->msg_controllen = user_message.msg_controllen; kmsg->msg_flags = user_message.msg_flags; + if (out_user_name_length != RT_NULL) + { + *out_user_name_length = kmsg->msg_namelen; + } + if (kmsg->msg_iovlen < 0 || (size_t)kmsg->msg_iovlen > SIZE_MAX / sizeof(*kmsg->msg_iov) || - kmsg->msg_namelen > sizeof(union lwp_sockaddr_buffer)) + (!receive && + kmsg->msg_namelen > sizeof(union lwp_sockaddr_buffer))) { return -EINVAL; } + if (receive) + { + if (kmsg->msg_name == RT_NULL) + { + kmsg->msg_namelen = 0; + } + else if (kmsg->msg_namelen > sizeof(union lwp_sockaddr_buffer)) + { + kmsg->msg_namelen = sizeof(union lwp_sockaddr_buffer); + } + if (kmsg->msg_control == RT_NULL) + { + kmsg->msg_controllen = 0; + } + } if (kmsg->msg_name != RT_NULL && !lwp_user_accessable(kmsg->msg_name, kmsg->msg_namelen)) { @@ -5862,6 +5905,7 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, sysret_t sys_recvmsg(int socket, struct musl_msghdr *msg, int flags) { int flgs, ret = -1; + int error = 0; struct msghdr kmsg; #ifdef ARCH_MM_MMU int index; @@ -5882,62 +5926,67 @@ sysret_t sys_recvmsg(int socket, struct musl_msghdr *msg, int flags) #ifdef ARCH_MM_MMU ret = copy_msghdr_from_user(&kmsg, msg, &uiov, &msg_control, - &msg_name, &buffer); + &msg_name, &buffer, &user_name_length, + RT_TRUE); - if (!ret) + if (ret < 0) { - user_name_length = kmsg.msg_namelen; - ret = recvmsg(socket, &kmsg, flgs); - - if (ret < 0) - { - goto _free_res; - } - - kiov = kmsg.msg_iov; - remaining = (size_t)ret; + return ret; + } + ret = recvmsg(socket, &kmsg, flgs); + if (ret < 0) + { + error = GET_ERRNO(); + } - for (index = 0; index < kmsg.msg_iovlen && remaining != 0; ++index) - { - size_t copy_length = kiov->iov_len; + if (ret < 0) + { + goto _free_res; + } - if (copy_length > remaining) - { - copy_length = remaining; - } - lwp_put_to_user(uiov->iov_base, kiov->iov_base, copy_length); - remaining -= copy_length; + kiov = kmsg.msg_iov; + remaining = (size_t)ret; - ++kiov; - ++uiov; - } + for (index = 0; index < kmsg.msg_iovlen && remaining != 0; ++index) + { + size_t copy_length = kiov->iov_len; - if (msg_control != RT_NULL && kmsg.msg_controllen != 0) - { - cmsg_level_lwip_2_muslc(&kmsg); - lwp_put_to_user(msg_control, kmsg.msg_control, - kmsg.msg_controllen); - } - if (msg_name != RT_NULL && kmsg.msg_name != RT_NULL) + if (copy_length > remaining) { - socklen_t name_length; - - name_length = lwp_sockaddr_to_user( - (struct musl_sockaddr *)msg_name, user_name_length, - (const union lwp_sockaddr_buffer *)kmsg.msg_name, - kmsg.msg_namelen); - lwp_put_to_user(&msg->msg_namelen, &name_length, - sizeof(name_length)); + copy_length = remaining; } - kmsg.msg_flags = netflags_lwip_2_muslc(kmsg.msg_flags); - lwp_put_to_user(&msg->msg_flags, &kmsg.msg_flags, sizeof(kmsg.msg_flags)); - lwp_put_to_user(&msg->msg_controllen, &kmsg.msg_controllen, - sizeof(kmsg.msg_controllen)); + lwp_put_to_user(uiov->iov_base, kiov->iov_base, copy_length); + remaining -= copy_length; + + ++kiov; + ++uiov; + } + + if (msg_control != RT_NULL && kmsg.msg_controllen != 0) + { + cmsg_level_lwip_2_muslc(&kmsg); + lwp_put_to_user(msg_control, kmsg.msg_control, + kmsg.msg_controllen); + } + if (msg_name != RT_NULL && kmsg.msg_name != RT_NULL) + { + socklen_t name_length; - _free_res: - kmem_put(buffer); - kmem_put(kmsg.msg_iov); + name_length = lwp_sockaddr_to_user( + (struct musl_sockaddr *)msg_name, user_name_length, + (const union lwp_sockaddr_buffer *)kmsg.msg_name, + kmsg.msg_namelen); + lwp_put_to_user(&msg->msg_namelen, &name_length, + sizeof(name_length)); } + kmsg.msg_flags = netflags_lwip_2_muslc(kmsg.msg_flags); + lwp_put_to_user(&msg->msg_flags, &kmsg.msg_flags, sizeof(kmsg.msg_flags)); + lwp_put_to_user(&msg->msg_controllen, &kmsg.msg_controllen, + sizeof(kmsg.msg_controllen)); + +_free_res: + kmem_put(buffer); + kmem_put(kmsg.msg_iov); #else kmsg.msg_name = msg->msg_name; kmsg.msg_namelen = msg->msg_namelen; @@ -5948,6 +5997,10 @@ sysret_t sys_recvmsg(int socket, struct musl_msghdr *msg, int flags) kmsg.msg_flags = msg->msg_flags; ret = recvmsg(socket, &kmsg, flgs); + if (ret < 0) + { + error = GET_ERRNO(); + } if (!ret) { @@ -5955,7 +6008,11 @@ sysret_t sys_recvmsg(int socket, struct musl_msghdr *msg, int flags) } #endif /* ARCH_MM_MMU */ - return (ret < 0 ? GET_ERRNO() : ret); + if (ret >= 0) + { + return ret; + } + return error != 0 ? error : ret; } /** @@ -6178,6 +6235,7 @@ sysret_t sys_recv(int socket, void *mem, size_t len, int flags) sysret_t sys_sendmsg(int socket, const struct musl_msghdr *msg, int flags) { int flgs, ret = -1; + int error = 0; struct msghdr kmsg; #ifdef ARCH_MM_MMU int index; @@ -6195,47 +6253,53 @@ sysret_t sys_sendmsg(int socket, const struct musl_msghdr *msg, int flags) #ifdef ARCH_MM_MMU ret = copy_msghdr_from_user(&kmsg, (struct musl_msghdr *)msg, &uiov, - &msg_control, &msg_name, &buffer); + &msg_control, &msg_name, &buffer, RT_NULL, + RT_FALSE); - if (!ret) + if (ret < 0) { - kiov = kmsg.msg_iov; + return ret; + } + kiov = kmsg.msg_iov; - for (index = 0; index < kmsg.msg_iovlen; ++index) - { - lwp_get_from_user(kiov->iov_base, uiov->iov_base, kiov->iov_len); + for (index = 0; index < kmsg.msg_iovlen; ++index) + { + lwp_get_from_user(kiov->iov_base, uiov->iov_base, kiov->iov_len); - ++kiov; - ++uiov; - } + ++kiov; + ++uiov; + } - if (msg_control != RT_NULL && kmsg.msg_controllen != 0) - { - lwp_get_from_user(kmsg.msg_control, msg_control, - kmsg.msg_controllen); - cmsg_level_muslc_2_lwip(&kmsg); - } - if (msg_name != RT_NULL && kmsg.msg_namelen != 0) - { - union lwp_sockaddr_buffer kernel_address; + if (msg_control != RT_NULL && kmsg.msg_controllen != 0) + { + lwp_get_from_user(kmsg.msg_control, msg_control, + kmsg.msg_controllen); + cmsg_level_muslc_2_lwip(&kmsg); + } + if (msg_name != RT_NULL && kmsg.msg_namelen != 0) + { + union lwp_sockaddr_buffer kernel_address; - ret = lwp_sockaddr_from_user(&kernel_address, - (struct musl_sockaddr *)msg_name, - kmsg.msg_namelen); - if (ret < 0) - { - kmem_put(buffer); - kmem_put(kmsg.msg_iov); - return ret; - } - rt_memcpy(kmsg.msg_name, &kernel_address, kmsg.msg_namelen); + ret = lwp_sockaddr_from_user(&kernel_address, + (struct musl_sockaddr *)msg_name, + kmsg.msg_namelen); + if (ret < 0) + { + kmem_put(buffer); + kmem_put(kmsg.msg_iov); + return ret; } + rt_memcpy(kmsg.msg_name, &kernel_address, kmsg.msg_namelen); + } - ret = sendmsg(socket, &kmsg, flgs); - - kmem_put(buffer); - kmem_put(kmsg.msg_iov); + ret = sendmsg(socket, &kmsg, flgs); + if (ret < 0) + { + error = GET_ERRNO(); } + + kmem_put(buffer); + kmem_put(kmsg.msg_iov); #else kmsg.msg_name = msg->msg_name; kmsg.msg_namelen = msg->msg_namelen; @@ -6246,10 +6310,18 @@ sysret_t sys_sendmsg(int socket, const struct musl_msghdr *msg, int flags) kmsg.msg_flags = msg->msg_flags; ret = sendmsg(socket, &kmsg, flgs); + if (ret < 0) + { + error = GET_ERRNO(); + } #endif /* ARCH_MM_MMU */ - return (ret < 0 ? GET_ERRNO() : ret); + if (ret >= 0) + { + return ret; + } + return error != 0 ? error : ret; } /** @@ -6530,7 +6602,9 @@ sysret_t sys_socketpair(int domain, int type, int protocol, int fd[2]) */ sysret_t sys_closesocket(int socket) { - return closesocket(socket); + sysret_t ret; + ret = closesocket(socket); + return ret; } #endif @@ -10619,6 +10693,14 @@ sysret_t sys_chmod(const char *pathname, mode_t mode) return (ret < 0 ? GET_ERRNO() : ret); } +sysret_t sys_fchmod(int fd, mode_t mode) +{ + int ret; + + ret = fchmod(fd, mode); + return (ret < 0 ? GET_ERRNO() : ret); +} + /** * @brief Change the ownership of a file or directory. * @@ -11497,6 +11579,7 @@ const static struct rt_syscall_def func_table[] = { SYSCALL_SIGN(sys_getppid), SYSCALL_SIGN(sys_fchdir), SYSCALL_SIGN(sys_chown), + SYSCALL_SIGN(sys_fchmod), }; const void *lwp_get_sys_api(rt_uint32_t number) diff --git a/tools/ci/bsp_buildings.py b/tools/ci/bsp_buildings.py index 5c6ade660bab..51b535fa7f5d 100644 --- a/tools/ci/bsp_buildings.py +++ b/tools/ci/bsp_buildings.py @@ -115,6 +115,15 @@ def is_env_enabled(name, default=False): return value.lower() not in ('', '0', 'false', 'no', 'off') +def is_smart_config(bsp): + """Return whether the BSP configuration builds RT-Smart.""" + config_file = os.path.join(rtt_root, 'bsp', bsp, '.config') + if not os.path.isfile(config_file): + return False + + with open(config_file, 'r', encoding='utf-8') as config: + return re.search(r'^CONFIG_RT_USING_SMART=y$', config.read(), re.MULTILINE) is not None + def get_ci_scons_args(scons_args=''): args = scons_args.strip() if os.getenv('RTT_TOOL_CHAIN') == 'armclang' and '--exec-path' not in args: @@ -175,6 +184,37 @@ def run_dist_build_check(bsp, scons_args=''): def build_bsp(bsp, scons_args='',name='default', pre_build_commands=None, post_build_command=None,build_check_result = None,bsp_build_env=None): + """Build a BSP with a toolchain matching its configuration.""" + build_env = {} + if is_smart_config(bsp): + smart_exec_path = os.getenv('RTT_SMART_EXEC_PATH') + smart_cc_prefix = os.getenv('RTT_SMART_CC_PREFIX') + if smart_exec_path: + build_env['RTT_EXEC_PATH'] = smart_exec_path + if smart_cc_prefix: + build_env['RTT_CC_PREFIX'] = smart_cc_prefix + if bsp_build_env is not None: + build_env.update(bsp_build_env) + + old_build_env = {key: os.environ.get(key) for key in build_env} + if build_env: + print("Setting environment variables:") + for key, value in build_env.items(): + print(f"{key}={value}") + os.environ[key] = value + + try: + return _build_bsp(bsp, scons_args, name, pre_build_commands, + post_build_command, build_check_result) + finally: + for key, value in old_build_env.items(): + if value is None: + os.environ.pop(key, None) + else: + os.environ[key] = value + + +def _build_bsp(bsp, scons_args='',name='default', pre_build_commands=None, post_build_command=None,build_check_result = None): """ build bsp. @@ -204,13 +244,6 @@ def build_bsp(bsp, scons_args='',name='default', pre_build_commands=None, post_b return False scons_args = get_ci_scons_args(scons_args) - - # 设置环境变量 - if bsp_build_env is not None: - print("Setting environment variables:") - for key, value in bsp_build_env.items(): - print(f"{key}={value}") - os.environ[key] = value # 设置环境变量 os.chdir(rtt_root) os.makedirs(f'{rtt_root}/output/bsp/{bsp}', exist_ok=True) if os.path.exists(f"{rtt_root}/bsp/{bsp}/Kconfig"):