summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorbernard <[email protected]>2026-08-23 07:43:50 +0800
committerRbb666 <[email protected]>2026-08-30 20:49:24 +0800
commitf02a869318c9df28ec2eab41f1a58795dc8a3f1b (patch)
tree6fd0a8fe38a9ee1980f45e6e7ae0137a415ed81e /components
parentbf38ee2130634ac6571e816dde81b04818d75444 (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.c276
-rw-r--r--components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h20
-rw-r--r--components/dfs/dfs_v2/filesystems/tmpfs/utest/tmpfs.c76
-rw-r--r--components/dfs/dfs_v2/include/dfs_file.h4
-rw-r--r--components/dfs/dfs_v2/src/dfs.c14
-rw-r--r--components/dfs/dfs_v2/src/dfs_file.c40
-rw-r--r--components/dfs/dfs_v2/src/dfs_posix.c96
-rw-r--r--components/dfs/dfs_v2/src/dfs_record_lock.c526
-rw-r--r--components/dfs/dfs_v2/src/dfs_vnode.c2
-rw-r--r--components/lwp/lwp_pid.c3
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--;
}