xiaoxiang781216 commented on code in PR #19536: URL: https://github.com/apache/nuttx/pull/19536#discussion_r3653035709
########## include/nuttx/fs/xipfs.h: ########## @@ -0,0 +1,168 @@ +/**************************************************************************** + * include/nuttx/fs/xipfs.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_FS_XIPFS_H +#define __INCLUDE_NUTTX_FS_XIPFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum length of one path component, not including the NUL terminator. + * Depth comes from the directory an entry belongs to rather than from its + * name, so this bounds a component and not a whole path -- which is what + * statfs reports it as, in f_namelen. + */ + +#define XIPFS_NAME_MAX 31 + +/* Longest path reported back to an application, separators included. A path + * is bounded only by the depth of the tree, so this is a reporting limit and + * not a filesystem one: a path longer than this is truncated from the front, + * which keeps the part that identifies the file. + */ + +#define XIPFS_PATH_MAX 127 Review Comment: why not use PATH_MAX ########## fs/xipfs/xipfs.h: ########## @@ -0,0 +1,380 @@ +/**************************************************************************** + * fs/xipfs/xipfs.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __FS_XIPFS_XIPFS_H +#define __FS_XIPFS_XIPFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/statfs.h> +#include <sys/types.h> +#include <stdbool.h> +#include <stdint.h> + +#include <nuttx/compiler.h> +#include <nuttx/fs/fs.h> +#include <nuttx/fs/xipfs.h> +#include <nuttx/mtd/mtd.h> +#include <nuttx/mutex.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* On-media identification */ + +#define XIPFS_SBLK_MAGIC XIPFS_MAGIC /* "XIPF", see sys/statfs.h */ +#define XIPFS_GEN_MAGIC 0x5847454e /* "XGEN" */ +#define XIPFS_VERSION 2 + +/* Volume geometry. + * + * Block 0 and block 1 hold the two superblock copies. The next + * XIPFS_META_NBLOCKS blocks form the metadata ring. Everything after that + * is the data region, allocated in whole erase blocks. + */ + +#define XIPFS_SBLK_A 0 +#define XIPFS_SBLK_B 1 +#define XIPFS_META_START 2 +#define XIPFS_META_NBLOCKS 4 +#define XIPFS_DATA_START (XIPFS_META_START + XIPFS_META_NBLOCKS) + +/* The smallest volume that can hold the superblocks, the metadata ring and + * at least one data block. + */ + +#define XIPFS_MIN_BLOCKS (XIPFS_DATA_START + 1) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* On-media superblock. Written once by mkfs into both block 0 and block 1. + * The CRC covers every byte preceding the crc field. + */ + +begin_packed_struct struct xipfs_sblk_s +{ + uint32_t magic; + uint32_t version; + uint32_t erasesize; + uint32_t blocksize; + uint32_t nblocks; /* Total erase blocks in the volume */ + uint32_t meta_start; /* First block of the metadata ring */ + uint32_t meta_nblocks; /* Length of the metadata ring */ + uint32_t data_start; /* First block of the data region */ + uint32_t data_nblocks; /* Length of the data region */ + uint32_t crc; +} end_packed_struct; + +/* On-media directory entry. One per file and one per directory, stored in + * the body of a metadata generation. + * + * Directories are records here and nowhere else. They are not objects in + * the data region, which is what keeps the power-safety story intact: mkdir + * and rmdir add or remove a record and commit one generation, exactly as + * create and unlink do, so there is never a multi-object update to journal + * or an orphan to collect at mount. + * + * 'name' is one path component, not a path. Depth comes from 'parent', so + * XIPFS_NAME_MAX bounds a component, which is what statfs reports it as. + * + * Padded to XIPFS_DIRENT_SIZE so that a whole number of dirents fits in a + * read/write block, which keeps the body write loop aligned without any + * straddling entries. + */ + +#define XIPFS_DIRENT_SIZE 64 + +/* Dirent flags */ + +#define XIPFS_DIRENT_DIR (1 << 0) /* The entry is a directory */ + +/* The root directory is implicit: it owns id 0 and has no record of its + * own, so it always exists and cannot be removed. + */ + +#define XIPFS_ROOT_ID 0 + +begin_packed_struct struct xipfs_dirent_s +{ + char name[XIPFS_NAME_MAX + 1]; /* 32 bytes, one component */ + uint32_t size; /* File size in bytes; 0 for a dir */ + uint32_t start_block; /* Extent block; 0 for a directory */ + uint32_t nblocks; /* Extent length; 0 for a directory */ + uint32_t flags; /* XIPFS_DIRENT_DIR */ + uint16_t id; /* Identity, unique, never 0 */ + uint16_t parent; /* Containing directory's id */ + uint8_t reserved[12]; /* Pad to XIPFS_DIRENT_SIZE */ +} end_packed_struct; + +/* On-media metadata generation header. + * + * This lives in the first read/write block of a metadata ring block; the + * dirent array follows in the blocks after it. The body is written first + * and the header last, so the single header write IS the commit point: a + * torn body leaves no valid header, and a torn header fails its own CRC. + * Either way mount falls back to the previous generation. + */ + +begin_packed_struct struct xipfs_genhdr_s +{ + uint32_t magic; + uint32_t seq; /* Monotonic generation number */ + uint32_t nentries; /* Number of dirents in body */ + uint32_t crc; /* CRC over header + body */ +} end_packed_struct; + +/* In-RAM directory entry. One per file and one per directory; a directory + * carries no extent, so its start_block, nblocks and size are all zero and + * everything that accounts for blocks has to skip it. + * + * For a file this is also the object the pin count lives on -- deliberately + * NOT the fd and NOT the open file struct, so that N mappings of one module + * produce a pin count of N and the extent only becomes movable when the + * last one goes away. + */ + +struct xipfs_extent_s +{ + FAR struct xipfs_extent_s *flink; + + /* Back pointer to the owning mount. The task teardown unmap path can + * only reach the extent, and must not consult the current task's group, + * so the extent has to be able to name its own filesystem. + */ + + FAR struct xipfs_mount_s *fs; + + /* One path component, not a path; depth comes from 'parent' */ + + char name[XIPFS_NAME_MAX + 1]; + + uint16_t id; /* Identity, unique, never 0 */ + uint16_t parent; /* Containing directory; XIPFS_ROOT_ID */ + bool isdir; /* A directory record, with no extent */ Review Comment: move after line 184 ########## boards/arm/rp23xx/pimoroni-pico-2-plus/scripts/Make.defs: ########## @@ -38,6 +38,9 @@ CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) AFLAGS := $(CFLAGS) -D__ASSEMBLY__ +MKNXFLAT = mknxflat +LDNXFLAT = ldnxflat Review Comment: should we move to arch/ common cmake/make file? ########## fs/xipfs/xipfs.h: ########## @@ -0,0 +1,380 @@ +/**************************************************************************** + * fs/xipfs/xipfs.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __FS_XIPFS_XIPFS_H +#define __FS_XIPFS_XIPFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/statfs.h> +#include <sys/types.h> +#include <stdbool.h> +#include <stdint.h> + +#include <nuttx/compiler.h> +#include <nuttx/fs/fs.h> +#include <nuttx/fs/xipfs.h> +#include <nuttx/mtd/mtd.h> +#include <nuttx/mutex.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* On-media identification */ + +#define XIPFS_SBLK_MAGIC XIPFS_MAGIC /* "XIPF", see sys/statfs.h */ +#define XIPFS_GEN_MAGIC 0x5847454e /* "XGEN" */ +#define XIPFS_VERSION 2 + +/* Volume geometry. + * + * Block 0 and block 1 hold the two superblock copies. The next + * XIPFS_META_NBLOCKS blocks form the metadata ring. Everything after that + * is the data region, allocated in whole erase blocks. + */ + +#define XIPFS_SBLK_A 0 +#define XIPFS_SBLK_B 1 +#define XIPFS_META_START 2 +#define XIPFS_META_NBLOCKS 4 +#define XIPFS_DATA_START (XIPFS_META_START + XIPFS_META_NBLOCKS) + +/* The smallest volume that can hold the superblocks, the metadata ring and + * at least one data block. + */ + +#define XIPFS_MIN_BLOCKS (XIPFS_DATA_START + 1) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* On-media superblock. Written once by mkfs into both block 0 and block 1. + * The CRC covers every byte preceding the crc field. + */ + +begin_packed_struct struct xipfs_sblk_s +{ + uint32_t magic; + uint32_t version; + uint32_t erasesize; + uint32_t blocksize; + uint32_t nblocks; /* Total erase blocks in the volume */ + uint32_t meta_start; /* First block of the metadata ring */ + uint32_t meta_nblocks; /* Length of the metadata ring */ + uint32_t data_start; /* First block of the data region */ + uint32_t data_nblocks; /* Length of the data region */ + uint32_t crc; +} end_packed_struct; + +/* On-media directory entry. One per file and one per directory, stored in + * the body of a metadata generation. + * + * Directories are records here and nowhere else. They are not objects in + * the data region, which is what keeps the power-safety story intact: mkdir + * and rmdir add or remove a record and commit one generation, exactly as + * create and unlink do, so there is never a multi-object update to journal + * or an orphan to collect at mount. + * + * 'name' is one path component, not a path. Depth comes from 'parent', so + * XIPFS_NAME_MAX bounds a component, which is what statfs reports it as. + * + * Padded to XIPFS_DIRENT_SIZE so that a whole number of dirents fits in a + * read/write block, which keeps the body write loop aligned without any + * straddling entries. + */ + +#define XIPFS_DIRENT_SIZE 64 Review Comment: move macro to Pre-processor section ########## include/nuttx/fs/xipfs.h: ########## @@ -0,0 +1,168 @@ +/**************************************************************************** + * include/nuttx/fs/xipfs.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_FS_XIPFS_H +#define __INCLUDE_NUTTX_FS_XIPFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum length of one path component, not including the NUL terminator. + * Depth comes from the directory an entry belongs to rather than from its + * name, so this bounds a component and not a whole path -- which is what + * statfs reports it as, in f_namelen. + */ + +#define XIPFS_NAME_MAX 31 + +/* Longest path reported back to an application, separators included. A path + * is bounded only by the depth of the tree, so this is a reporting limit and + * not a filesystem one: a path longer than this is truncated from the front, + * which keeps the part that identifies the file. + */ + +#define XIPFS_PATH_MAX 127 + +/* Reason codes returned in struct xipfs_defrag_result_s.reason. + * + * The distinction that matters to the caller is transient (PINS, RAM, + * BUDGET -- retrying later may help) versus permanent (FULL -- it will + * not). The caller normally asked because an allocation returned + * -ENOSPC, so largest_free_run tells it directly whether a retry of that + * allocation can now succeed. + */ + +#define XIPFS_DEFRAG_DONE 0 /* Nothing left to compact */ +#define XIPFS_DEFRAG_BLOCKED_PINS 1 /* Blocked by a live XIP mapping */ +#define XIPFS_DEFRAG_BLOCKED_RAM 2 /* Transient resource shortage */ +#define XIPFS_DEFRAG_TIME_BUDGET 3 /* Ran out of the caller's budget */ +#define XIPFS_DEFRAG_ERROR 4 /* Media error; stopped cleanly */ +#define XIPFS_DEFRAG_BLOCKED_OPEN 5 /* Blocked by a merely open file */ + +/* BLOCKED_PINS and BLOCKED_OPEN are deliberately distinct because the + * caller resolves them differently: a pinned extent needs a module to be + * unloaded, whereas an open one only needs a descriptor to be closed. Issue + * the ioctl on a descriptor for the mountpoint directory to avoid the + * self-inflicted case: a descriptor for a file inside the volume holds that + * file open, and the pass then reports BLOCKED_OPEN for the caller's own + * file. + */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Outcome of one xipfs defragmentation pass. Returned by the + * XIPFSIOC_DEFRAG ioctl. + */ + +struct xipfs_defrag_result_s +{ + size_t largest_free_run; /* Bytes in the largest contiguous free run */ + uint32_t blocks_reclaimed; /* Erase blocks coalesced into free space */ + uint32_t blocks_pinned; /* Blocks skipped because pin count > 0 */ + uint32_t extents_moved; /* Number of atomic relocations performed */ + int reason; /* One of XIPFS_DEFRAG_* */ +}; + +/* Argument to the XIPFSIOC_DEFRAG ioctl */ + +struct xipfs_defrag_arg_s +{ + uint32_t max_ms; /* 0 means "no time budget" */ + struct xipfs_defrag_result_s result; /* Filled in on return */ +}; + +/* One entry returned by the XIPFSIOC_LISTPINNED ioctl. Without this, + * "blocked by pins" is a dead end the caller cannot resolve; with it the + * application can unload an idle module and re-trigger defrag. + */ + +struct xipfs_pinned_entry_s +{ + char path[XIPFS_PATH_MAX + 1]; /* Relative to the mountpoint */ + uint32_t start_block; + uint32_t nblocks; + uint32_t pincount; +}; + +/* Argument to the XIPFSIOC_LISTPINNED ioctl */ + +struct xipfs_pinned_arg_s +{ + FAR struct xipfs_pinned_entry_s *entries; /* Caller supplied array */ + size_t nentries; /* Capacity of that array */ + size_t count; /* OUT: entries filled in */ +}; + +/* Argument to the XIPFSIOC_EXTENTINFO ioctl. Reports the physical + * placement of the file behind the file descriptor, which is what the + * contiguity invariant tests assert against. + */ + +struct xipfs_extent_info_s +{ + uint32_t start_block; + uint32_t nblocks; + uint32_t erasesize; + uint32_t size; + uint32_t pincount; + uint32_t data_start; /* First block of the data region */ + uint32_t data_nblocks; /* Length of the data region */ + uintptr_t xipaddr; /* Direct flash address, or 0 if not XIP capable */ +}; + +/* Fault-injection mode carried in the XIPFSIOC_FAULTINJECT argument. + * + * CLEAN models a power loss that stops the failing write or erase before it + * perturbs the medium at all, leaving the target exactly as it was. TORN + * models the harder real case: an interrupted NOR program leaves the first + * half of a page written and the rest unprogrammed, and an interrupted erase + * leaves the first half of a sector erased and the rest holding old + * contents. A torn generation is what forces the mount-time CRC to do real + * work -- reject a half-formed generation rather than trust it -- which the + * clean model, where an operation either happens whole or not at all, never + * exercises. + */ + +#define XIPFS_FAULT_CLEAN 0 +#define XIPFS_FAULT_TORN 1 Review Comment: move to macro section ########## fs/xipfs/xipfs.h: ########## @@ -0,0 +1,380 @@ +/**************************************************************************** + * fs/xipfs/xipfs.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __FS_XIPFS_XIPFS_H +#define __FS_XIPFS_XIPFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/statfs.h> +#include <sys/types.h> +#include <stdbool.h> +#include <stdint.h> + +#include <nuttx/compiler.h> +#include <nuttx/fs/fs.h> +#include <nuttx/fs/xipfs.h> +#include <nuttx/mtd/mtd.h> +#include <nuttx/mutex.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* On-media identification */ + +#define XIPFS_SBLK_MAGIC XIPFS_MAGIC /* "XIPF", see sys/statfs.h */ +#define XIPFS_GEN_MAGIC 0x5847454e /* "XGEN" */ +#define XIPFS_VERSION 2 + +/* Volume geometry. + * + * Block 0 and block 1 hold the two superblock copies. The next + * XIPFS_META_NBLOCKS blocks form the metadata ring. Everything after that + * is the data region, allocated in whole erase blocks. + */ + +#define XIPFS_SBLK_A 0 +#define XIPFS_SBLK_B 1 +#define XIPFS_META_START 2 +#define XIPFS_META_NBLOCKS 4 +#define XIPFS_DATA_START (XIPFS_META_START + XIPFS_META_NBLOCKS) + +/* The smallest volume that can hold the superblocks, the metadata ring and + * at least one data block. + */ + +#define XIPFS_MIN_BLOCKS (XIPFS_DATA_START + 1) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* On-media superblock. Written once by mkfs into both block 0 and block 1. + * The CRC covers every byte preceding the crc field. + */ + +begin_packed_struct struct xipfs_sblk_s +{ + uint32_t magic; + uint32_t version; + uint32_t erasesize; + uint32_t blocksize; + uint32_t nblocks; /* Total erase blocks in the volume */ + uint32_t meta_start; /* First block of the metadata ring */ + uint32_t meta_nblocks; /* Length of the metadata ring */ + uint32_t data_start; /* First block of the data region */ + uint32_t data_nblocks; /* Length of the data region */ + uint32_t crc; +} end_packed_struct; + +/* On-media directory entry. One per file and one per directory, stored in + * the body of a metadata generation. + * + * Directories are records here and nowhere else. They are not objects in + * the data region, which is what keeps the power-safety story intact: mkdir + * and rmdir add or remove a record and commit one generation, exactly as + * create and unlink do, so there is never a multi-object update to journal + * or an orphan to collect at mount. + * + * 'name' is one path component, not a path. Depth comes from 'parent', so + * XIPFS_NAME_MAX bounds a component, which is what statfs reports it as. + * + * Padded to XIPFS_DIRENT_SIZE so that a whole number of dirents fits in a + * read/write block, which keeps the body write loop aligned without any + * straddling entries. + */ + +#define XIPFS_DIRENT_SIZE 64 + +/* Dirent flags */ + +#define XIPFS_DIRENT_DIR (1 << 0) /* The entry is a directory */ + +/* The root directory is implicit: it owns id 0 and has no record of its + * own, so it always exists and cannot be removed. + */ + +#define XIPFS_ROOT_ID 0 + +begin_packed_struct struct xipfs_dirent_s +{ + char name[XIPFS_NAME_MAX + 1]; /* 32 bytes, one component */ + uint32_t size; /* File size in bytes; 0 for a dir */ + uint32_t start_block; /* Extent block; 0 for a directory */ + uint32_t nblocks; /* Extent length; 0 for a directory */ + uint32_t flags; /* XIPFS_DIRENT_DIR */ Review Comment: align `*/` ########## include/nuttx/fs/xipfs.h: ########## @@ -0,0 +1,168 @@ +/**************************************************************************** + * include/nuttx/fs/xipfs.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_FS_XIPFS_H +#define __INCLUDE_NUTTX_FS_XIPFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum length of one path component, not including the NUL terminator. + * Depth comes from the directory an entry belongs to rather than from its + * name, so this bounds a component and not a whole path -- which is what + * statfs reports it as, in f_namelen. + */ + +#define XIPFS_NAME_MAX 31 + +/* Longest path reported back to an application, separators included. A path + * is bounded only by the depth of the tree, so this is a reporting limit and + * not a filesystem one: a path longer than this is truncated from the front, + * which keeps the part that identifies the file. + */ + +#define XIPFS_PATH_MAX 127 + +/* Reason codes returned in struct xipfs_defrag_result_s.reason. + * + * The distinction that matters to the caller is transient (PINS, RAM, + * BUDGET -- retrying later may help) versus permanent (FULL -- it will + * not). The caller normally asked because an allocation returned + * -ENOSPC, so largest_free_run tells it directly whether a retry of that + * allocation can now succeed. + */ + +#define XIPFS_DEFRAG_DONE 0 /* Nothing left to compact */ +#define XIPFS_DEFRAG_BLOCKED_PINS 1 /* Blocked by a live XIP mapping */ +#define XIPFS_DEFRAG_BLOCKED_RAM 2 /* Transient resource shortage */ +#define XIPFS_DEFRAG_TIME_BUDGET 3 /* Ran out of the caller's budget */ +#define XIPFS_DEFRAG_ERROR 4 /* Media error; stopped cleanly */ +#define XIPFS_DEFRAG_BLOCKED_OPEN 5 /* Blocked by a merely open file */ + +/* BLOCKED_PINS and BLOCKED_OPEN are deliberately distinct because the + * caller resolves them differently: a pinned extent needs a module to be + * unloaded, whereas an open one only needs a descriptor to be closed. Issue + * the ioctl on a descriptor for the mountpoint directory to avoid the + * self-inflicted case: a descriptor for a file inside the volume holds that + * file open, and the pass then reports BLOCKED_OPEN for the caller's own + * file. + */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Outcome of one xipfs defragmentation pass. Returned by the + * XIPFSIOC_DEFRAG ioctl. + */ + +struct xipfs_defrag_result_s +{ + size_t largest_free_run; /* Bytes in the largest contiguous free run */ + uint32_t blocks_reclaimed; /* Erase blocks coalesced into free space */ + uint32_t blocks_pinned; /* Blocks skipped because pin count > 0 */ + uint32_t extents_moved; /* Number of atomic relocations performed */ + int reason; /* One of XIPFS_DEFRAG_* */ +}; + +/* Argument to the XIPFSIOC_DEFRAG ioctl */ + +struct xipfs_defrag_arg_s +{ + uint32_t max_ms; /* 0 means "no time budget" */ + struct xipfs_defrag_result_s result; /* Filled in on return */ +}; + +/* One entry returned by the XIPFSIOC_LISTPINNED ioctl. Without this, + * "blocked by pins" is a dead end the caller cannot resolve; with it the + * application can unload an idle module and re-trigger defrag. + */ + +struct xipfs_pinned_entry_s +{ + char path[XIPFS_PATH_MAX + 1]; /* Relative to the mountpoint */ + uint32_t start_block; + uint32_t nblocks; + uint32_t pincount; +}; + +/* Argument to the XIPFSIOC_LISTPINNED ioctl */ + +struct xipfs_pinned_arg_s +{ + FAR struct xipfs_pinned_entry_s *entries; /* Caller supplied array */ + size_t nentries; /* Capacity of that array */ + size_t count; /* OUT: entries filled in */ +}; + +/* Argument to the XIPFSIOC_EXTENTINFO ioctl. Reports the physical + * placement of the file behind the file descriptor, which is what the + * contiguity invariant tests assert against. + */ + +struct xipfs_extent_info_s +{ + uint32_t start_block; + uint32_t nblocks; + uint32_t erasesize; + uint32_t size; + uint32_t pincount; + uint32_t data_start; /* First block of the data region */ + uint32_t data_nblocks; /* Length of the data region */ Review Comment: keep the `*/` align each other ########## include/nuttx/fs/xipfs.h: ########## @@ -0,0 +1,168 @@ +/**************************************************************************** + * include/nuttx/fs/xipfs.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_FS_XIPFS_H +#define __INCLUDE_NUTTX_FS_XIPFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum length of one path component, not including the NUL terminator. + * Depth comes from the directory an entry belongs to rather than from its + * name, so this bounds a component and not a whole path -- which is what + * statfs reports it as, in f_namelen. + */ + +#define XIPFS_NAME_MAX 31 Review Comment: why not use NAME_MAX directly ########## fs/xipfs/xipfs.h: ########## @@ -0,0 +1,380 @@ +/**************************************************************************** + * fs/xipfs/xipfs.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __FS_XIPFS_XIPFS_H +#define __FS_XIPFS_XIPFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/statfs.h> +#include <sys/types.h> +#include <stdbool.h> +#include <stdint.h> + +#include <nuttx/compiler.h> +#include <nuttx/fs/fs.h> +#include <nuttx/fs/xipfs.h> +#include <nuttx/mtd/mtd.h> +#include <nuttx/mutex.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* On-media identification */ + +#define XIPFS_SBLK_MAGIC XIPFS_MAGIC /* "XIPF", see sys/statfs.h */ +#define XIPFS_GEN_MAGIC 0x5847454e /* "XGEN" */ +#define XIPFS_VERSION 2 + +/* Volume geometry. + * + * Block 0 and block 1 hold the two superblock copies. The next + * XIPFS_META_NBLOCKS blocks form the metadata ring. Everything after that + * is the data region, allocated in whole erase blocks. + */ + +#define XIPFS_SBLK_A 0 +#define XIPFS_SBLK_B 1 +#define XIPFS_META_START 2 +#define XIPFS_META_NBLOCKS 4 +#define XIPFS_DATA_START (XIPFS_META_START + XIPFS_META_NBLOCKS) + +/* The smallest volume that can hold the superblocks, the metadata ring and + * at least one data block. + */ + +#define XIPFS_MIN_BLOCKS (XIPFS_DATA_START + 1) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* On-media superblock. Written once by mkfs into both block 0 and block 1. + * The CRC covers every byte preceding the crc field. + */ + +begin_packed_struct struct xipfs_sblk_s +{ + uint32_t magic; + uint32_t version; + uint32_t erasesize; + uint32_t blocksize; + uint32_t nblocks; /* Total erase blocks in the volume */ + uint32_t meta_start; /* First block of the metadata ring */ + uint32_t meta_nblocks; /* Length of the metadata ring */ + uint32_t data_start; /* First block of the data region */ + uint32_t data_nblocks; /* Length of the data region */ + uint32_t crc; +} end_packed_struct; + +/* On-media directory entry. One per file and one per directory, stored in + * the body of a metadata generation. + * + * Directories are records here and nowhere else. They are not objects in + * the data region, which is what keeps the power-safety story intact: mkdir + * and rmdir add or remove a record and commit one generation, exactly as + * create and unlink do, so there is never a multi-object update to journal + * or an orphan to collect at mount. + * + * 'name' is one path component, not a path. Depth comes from 'parent', so + * XIPFS_NAME_MAX bounds a component, which is what statfs reports it as. + * + * Padded to XIPFS_DIRENT_SIZE so that a whole number of dirents fits in a + * read/write block, which keeps the body write loop aligned without any + * straddling entries. + */ + +#define XIPFS_DIRENT_SIZE 64 + +/* Dirent flags */ + +#define XIPFS_DIRENT_DIR (1 << 0) /* The entry is a directory */ + +/* The root directory is implicit: it owns id 0 and has no record of its + * own, so it always exists and cannot be removed. + */ + +#define XIPFS_ROOT_ID 0 + +begin_packed_struct struct xipfs_dirent_s +{ + char name[XIPFS_NAME_MAX + 1]; /* 32 bytes, one component */ + uint32_t size; /* File size in bytes; 0 for a dir */ + uint32_t start_block; /* Extent block; 0 for a directory */ + uint32_t nblocks; /* Extent length; 0 for a directory */ + uint32_t flags; /* XIPFS_DIRENT_DIR */ + uint16_t id; /* Identity, unique, never 0 */ + uint16_t parent; /* Containing directory's id */ + uint8_t reserved[12]; /* Pad to XIPFS_DIRENT_SIZE */ +} end_packed_struct; + +/* On-media metadata generation header. + * + * This lives in the first read/write block of a metadata ring block; the + * dirent array follows in the blocks after it. The body is written first + * and the header last, so the single header write IS the commit point: a + * torn body leaves no valid header, and a torn header fails its own CRC. + * Either way mount falls back to the previous generation. + */ + +begin_packed_struct struct xipfs_genhdr_s +{ + uint32_t magic; + uint32_t seq; /* Monotonic generation number */ + uint32_t nentries; /* Number of dirents in body */ + uint32_t crc; /* CRC over header + body */ +} end_packed_struct; + +/* In-RAM directory entry. One per file and one per directory; a directory + * carries no extent, so its start_block, nblocks and size are all zero and + * everything that accounts for blocks has to skip it. + * + * For a file this is also the object the pin count lives on -- deliberately + * NOT the fd and NOT the open file struct, so that N mappings of one module + * produce a pin count of N and the extent only becomes movable when the + * last one goes away. + */ + +struct xipfs_extent_s +{ + FAR struct xipfs_extent_s *flink; + + /* Back pointer to the owning mount. The task teardown unmap path can + * only reach the extent, and must not consult the current task's group, + * so the extent has to be able to name its own filesystem. + */ + + FAR struct xipfs_mount_s *fs; + + /* One path component, not a path; depth comes from 'parent' */ + + char name[XIPFS_NAME_MAX + 1]; + + uint16_t id; /* Identity, unique, never 0 */ + uint16_t parent; /* Containing directory; XIPFS_ROOT_ID */ + bool isdir; /* A directory record, with no extent */ + uint32_t size; + uint32_t start_block; + uint32_t nblocks; + uint32_t pincount; /* Mappings that alias flash (true XIP) */ + uint32_t openrefs; /* Open file descriptors */ + bool writing; /* Create-time write still in progress */ + bool unlinked; /* Detached from directory, awaiting free */ +}; + +/* In-RAM mount state */ + +struct xipfs_mount_s +{ + FAR struct inode *driver; + FAR struct mtd_dev_s *mtd; + struct mtd_geometry_s geo; + + /* Direct address of the media, from BIOC_XIPBASE. NULL when the + * underlying driver cannot expose one, in which case XIP mappings are + * impossible and strict requests fail with -ENXIO. + */ + + FAR uint8_t *xipbase; + + uint32_t meta_start; + uint32_t meta_nblocks; + uint32_t meta_slot; /* Ring slot holding the live generation */ + uint32_t meta_seq; /* Sequence number of that generation */ + uint32_t data_start; + uint32_t data_nblocks; + + FAR uint8_t *bitmap; /* Free bitmap over the data region */ + size_t bitmapsize; + + /* Staging buffer for defrag relocation. Reserved once at bind time so + * that a relocation can never fail part way through because a transient + * allocation did not succeed. + */ + + FAR uint8_t *stage; + + /* Scratch for building and verifying a metadata generation. Separate + * from 'stage' because defrag commits a generation while its relocation + * copy is in flight. + */ + + FAR uint8_t *metabuf; + + uint32_t entries_per_blk; /* Dirents in one read/write block */ + uint32_t max_entries; /* Dirents that fit in one ring block */ + + FAR struct xipfs_extent_s *extents; + uint32_t nextents; + + /* Single guard over extent metadata, the allocator and the pin counts. + * The map path holds it across "range check -> resolve -> take pin" and + * defrag holds it across "observe pincount == 0 -> relocate", so a new + * mapping cannot slip in between the compactor's check and its move. + */ + + rmutex_t lock; + + bool unmounted; + +#ifdef CONFIG_FS_XIPFS_FAULT_INJECT + int32_t fault_countdown; /* Negative disables injection */ + uint8_t fault_mode; /* XIPFS_FAULT_CLEAN or XIPFS_FAULT_TORN */ + bool media_dead; Review Comment: move before line 245 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
