diff options
| author | bernard <[email protected]> | 2026-08-23 07:43:50 +0800 |
|---|---|---|
| committer | Rbb666 <[email protected]> | 2026-08-30 20:49:24 +0800 |
| commit | f02a869318c9df28ec2eab41f1a58795dc8a3f1b (patch) | |
| tree | 6fd0a8fe38a9ee1980f45e6e7ae0137a415ed81e /components | |
| parent | bf38ee2130634ac6571e816dde81b04818d75444 (diff) | |
[dfs][posix] Add record locks, fchmod, and tmpfs metadata
为 DFS v2 增加 POSIX 记录锁、fchmod,以及 tmpfs 的权限和时间元数据。
进程退出时通过 dfs_fdtable_drop_fd 释放文件描述符和记录锁。
Diffstat (limited to 'components')
| -rw-r--r-- | components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c | 276 | ||||
| -rw-r--r-- | components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h | 20 | ||||
| -rw-r--r-- | components/dfs/dfs_v2/filesystems/tmpfs/utest/tmpfs.c | 76 | ||||
| -rw-r--r-- | components/dfs/dfs_v2/include/dfs_file.h | 4 | ||||
| -rw-r--r-- | components/dfs/dfs_v2/src/dfs.c | 14 | ||||
| -rw-r--r-- | components/dfs/dfs_v2/src/dfs_file.c | 40 | ||||
| -rw-r--r-- | components/dfs/dfs_v2/src/dfs_posix.c | 96 | ||||
| -rw-r--r-- | components/dfs/dfs_v2/src/dfs_record_lock.c | 526 | ||||
| -rw-r--r-- | components/dfs/dfs_v2/src/dfs_vnode.c | 2 | ||||
| -rw-r--r-- | components/lwp/lwp_pid.c | 3 |
10 files changed, 943 insertions, 114 deletions
diff --git a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c index cc511415a3..0f1d42e9f8 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 <rtdbg.h> #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 @@ __next_dir: } 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 @@ __next_dir: 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 0807f06d19..ee3124f69e 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 <rtthread.h> #include <dfs_vfs.h> -#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 647944a714..502c472718 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 <rtthread.h> #include <stdlib.h> #include <errno.h> +#include <dirent.h> #include <fcntl.h> #include <unistd.h> #include <msh.h> @@ -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 280d0dbcb9..60401f7ef0 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 92c688a8a0..f1601f0003 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 @@ _EXIT: 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 6b16159396..970b74c6ca 100644 --- a/components/dfs/dfs_v2/src/dfs_file.c +++ b/components/dfs/dfs_v2/src/dfs_file.c @@ -558,7 +558,7 @@ _ERR_RET: * @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 7351578656..d0deb50c77 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); @@ -1331,7 +1373,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 0000000000..1d159c0257 --- /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 <limits.h> + +#include <dfs.h> +#include <dfs_file.h> +#include <rtservice.h> + +#ifdef RT_USING_SMART +#include <lwp.h> +#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 462f94e05e..0b133c1d23 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/lwp/lwp_pid.c b/components/lwp/lwp_pid.c index 82f205a694..12a4dde86f 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--; } |
