From 5d0b12e45942d04310447d2938ed42d4c9dc7084 Mon Sep 17 00:00:00 2001 From: Jacek Maksymowicz Date: Thu, 16 Nov 2023 14:20:25 +0100 Subject: [PATCH] ext2: Add ability to mount devices and filesystems Fix setting attributes of newly created file Fixes phoenix-rtos/phoenix-rtos-project#114 DONE: RTOS-675 --- ext2/dir.c | 7 ++-- ext2/ext2.c | 90 ++++++++++++++++++++++++++++++-------------------- ext2/ext2.h | 5 ++- ext2/libext2.c | 63 ++++++++++++++++++++--------------- ext2/obj.c | 22 +++++++----- ext2/obj.h | 18 +++++----- 6 files changed, 119 insertions(+), 86 deletions(-) diff --git a/ext2/dir.c b/ext2/dir.c index 2ff8ac34..2a5ad791 100644 --- a/ext2/dir.c +++ b/ext2/dir.c @@ -176,9 +176,6 @@ int _ext2_dir_read(ext2_t *fs, ext2_obj_t *dir, offs_t offs, struct dirent *res, res->d_name[entry->len] = '\0'; free(entry); - if ((dir->flags & OFLAG_MOUNTPOINT) && !strncmp(res->d_name, "..", 2)) - res->d_ino = (ino_t)dir->mnt.id; - dir->inode->atime = time(NULL); return res->d_reclen; @@ -251,6 +248,10 @@ int _ext2_dir_add(ext2_t *fs, ext2_obj_t *dir, const char *name, size_t len, uin entry->type = DIRENT_CHRDEV; else if (S_ISBLK(mode)) entry->type = DIRENT_BLKDEV; + else if (S_ISFIFO(mode)) + entry->type = DIRENT_FIFO; + else if (S_ISSOCK(mode)) + entry->type = DIRENT_SOCK; else if (S_ISREG(mode)) entry->type = DIRENT_FILE; else diff --git a/ext2/ext2.c b/ext2/ext2.c index 0b02e0c1..6f2096b2 100644 --- a/ext2/ext2.c +++ b/ext2/ext2.c @@ -39,9 +39,10 @@ int ext2_create(ext2_t *fs, id_t id, const char *name, size_t len, oid_t *dev, u if (ext2_link(fs, id, name, len, obj->id) < 0) return ext2_obj_destroy(fs, obj); - /* FIXME: FIFO */ - if (S_ISCHR(obj->inode->mode) || S_ISBLK(obj->inode->mode)) + if (EXT2_ISDEV(obj->inode->mode)) { memcpy(&obj->dev, dev, sizeof(oid_t)); + obj->flags |= OFLAG_MOUNTPOINT; + } *res = obj->id; ext2_obj_put(fs, obj); @@ -81,22 +82,25 @@ int ext2_lookup(ext2_t *fs, id_t id, const char *name, size_t len, oid_t *res, o int err; res->port = fs->port; - if (!len || (name == NULL)) + if ((len == 0) || (name == NULL)) { return -EINVAL; + } - if ((dir = ext2_obj_get(fs, id)) == NULL) + if ((dir = ext2_obj_get(fs, id)) == NULL) { return -ENOENT; + } + mutexLock(dir->lock); for (i = 0, j = 0; i < len; i = j + 1, dir = obj) { - while ((i < len) && (name[i] == '/')) + while ((i < len) && (name[i] == '/')) { i++; + } j = i + 1; - while ((j < len) && (name[j] != '/')) + while ((j < len) && (name[j] != '/')) { j++; - - mutexLock(dir->lock); + } do { if (i >= len) { @@ -109,10 +113,13 @@ int ext2_lookup(ext2_t *fs, id_t id, const char *name, size_t len, oid_t *res, o break; } - if ((err = _ext2_dir_search(fs, dir, name + i, j - i, &res->id)) < 0) + err = _ext2_dir_search(fs, dir, name + i, j - i, &res->id); + if (err < 0) { break; + } - if ((obj = ext2_obj_get(fs, res->id)) == NULL) { + obj = ext2_obj_get(fs, res->id); + if (obj == NULL) { ext2_unlink(fs, dir->id, name + i, j - i); err = -ENOENT; break; @@ -122,20 +129,18 @@ int ext2_lookup(ext2_t *fs, id_t id, const char *name, size_t len, oid_t *res, o mutexUnlock(dir->lock); ext2_obj_put(fs, dir); - if (err < 0) + if (err < 0) { return err; - } - - mutexLock(obj->lock); + } - if (S_ISCHR(obj->inode->mode) || S_ISBLK(obj->inode->mode)) { - memcpy(dev, &obj->dev, sizeof(oid_t)); - } - else { - dev->port = fs->port; - dev->id = res->id; + mutexLock(obj->lock); + if (EXT2_IS_MOUNTPOINT(obj) && S_ISDIR(obj->inode->mode)) { + break; + } } + *dev = EXT2_IS_MOUNTPOINT(obj) ? obj->dev : *res; + mutexUnlock(obj->lock); ext2_obj_put(fs, obj); @@ -189,17 +194,15 @@ ssize_t ext2_read(ext2_t *fs, id_t id, offs_t offs, char *buff, size_t len) mutexLock(obj->lock); if (S_ISDIR(obj->inode->mode)) { - if ((obj->flags & (OFLAG_MOUNT | OFLAG_MOUNTPOINT)) && (len >= sizeof(oid_t))) { - ret = sizeof(oid_t); - memcpy(buff, &obj->mnt, ret); + if (EXT2_IS_MOUNTPOINT(obj)) { + ret = -EINVAL; } else { ret = _ext2_dir_read(fs, obj, offs, (struct dirent *)buff, len); } } - else if ((S_ISCHR(obj->inode->mode) || S_ISBLK(obj->inode->mode)) && (len >= sizeof(oid_t))) { - ret = sizeof(oid_t); - memcpy(buff, &obj->dev, ret); + else if (EXT2_ISDEV(obj->inode->mode)) { + ret = -EINVAL; } else { ret = _ext2_file_read(fs, obj, offs, buff, len); @@ -222,10 +225,12 @@ ssize_t ext2_write(ext2_t *fs, id_t id, offs_t offs, const char *buff, size_t le mutexLock(obj->lock); - if (S_ISDIR(obj->inode->mode) || S_ISCHR(obj->inode->mode) || S_ISBLK(obj->inode->mode)) + if (S_ISDIR(obj->inode->mode) || EXT2_ISDEV(obj->inode->mode)) { ret = -EINVAL; - else + } + else { ret = _ext2_file_write(fs, obj, offs, buff, len); + } mutexUnlock(obj->lock); ext2_obj_put(fs, obj); @@ -317,7 +322,7 @@ int ext2_getattr(ext2_t *fs, id_t id, int type, long long *attr) else if (S_ISREG(obj->inode->mode)) { *attr = otFile; } - else if (S_ISCHR(obj->inode->mode) || S_ISBLK(obj->inode->mode) || S_ISFIFO(obj->inode->mode)) { + else if (EXT2_ISDEV(obj->inode->mode)) { *attr = otDev; } else if (S_ISLNK(obj->inode->mode)) { @@ -360,7 +365,7 @@ int ext2_getattr(ext2_t *fs, id_t id, int type, long long *attr) } -int ext2_setattr(ext2_t *fs, id_t id, int type, long long attr) +int ext2_setattr(ext2_t *fs, id_t id, int type, long long attr, void *data, size_t len) { ext2_obj_t *obj; int err = EOK; @@ -402,6 +407,24 @@ int ext2_setattr(ext2_t *fs, id_t id, int type, long long attr) obj->inode->atime = attr; break; + case atDev: + if (data != NULL && len == sizeof(oid_t)) { + oid_t dev; + memcpy(&dev, data, len); + if ((dev.port == fs->port) && (dev.id == id)) { + obj->flags &= ~OFLAG_MOUNTPOINT; + } + else { + obj->dev = dev; + obj->flags |= OFLAG_MOUNTPOINT; + } + } + else { + err = -EINVAL; + } + break; + + default: /* unknown / invalid attribute to set */ err = -EINVAL; @@ -530,12 +553,7 @@ int ext2_unlink(ext2_t *fs, id_t id, const char *name, size_t len) mutexLock(obj->lock); do { - if (obj->flags & (OFLAG_MOUNTPOINT | OFLAG_MOUNT)) { - err = -EBUSY; - break; - } - - if (S_ISDIR(obj->inode->mode) && !_ext2_dir_empty(fs, obj)) { + if (S_ISDIR(obj->inode->mode) && (EXT2_IS_MOUNTPOINT(obj) || !_ext2_dir_empty(fs, obj))) { err = -ENOTEMPTY; break; } diff --git a/ext2/ext2.h b/ext2/ext2.h index 976a0558..f2403053 100644 --- a/ext2/ext2.h +++ b/ext2/ext2.h @@ -30,6 +30,9 @@ #define MAX_OBJECTS 512 /* Max number of filesystem objects in use */ +#define EXT2_ISDEV(x) (S_ISCHR(x) || S_ISBLK(x) || S_ISFIFO(x) || S_ISSOCK(x)) + + /* Filesystem common data types forward declaration */ typedef struct _ext2_sb_t ext2_sb_t; /* SuperBlock */ typedef struct _ext2_gd_t ext2_gd_t; /* Group Descriptor*/ @@ -108,7 +111,7 @@ extern int ext2_getattr(ext2_t *fs, id_t id, int type, long long *attr); /* Sets file attributes */ -extern int ext2_setattr(ext2_t *fs, id_t id, int type, long long attr); +extern int ext2_setattr(ext2_t *fs, id_t id, int type, long long attr, void *data, size_t len); /* Adds a link */ diff --git a/ext2/libext2.c b/ext2/libext2.c index d20d68f3..790898bb 100644 --- a/ext2/libext2.c +++ b/ext2/libext2.c @@ -25,48 +25,62 @@ #include "libext2.h" -static int libext2_create(void *info, oid_t *oid, const char *name, oid_t *dev, unsigned mode, int type, oid_t *res) +static int libext2_create(void *info, oid_t *dir, const char *name, oid_t *oid, unsigned mode, int type, oid_t *dev) { ext2_t *fs = (ext2_t *)info; ext2_obj_t *obj; oid_t devOther; int ret; - dev->port = fs->port; + oid->port = fs->port; switch (type) { case otDir: - mode |= S_IFDIR; + if (!S_ISDIR(mode)) { + mode &= ALLPERMS; + mode |= S_IFDIR; + } break; case otFile: - mode |= S_IFREG; + if (!S_ISREG(mode)) { + mode &= ALLPERMS; + mode |= S_IFREG; + } break; case otDev: - mode &= 0x1ff; - mode |= S_IFCHR; + if (!EXT2_ISDEV(mode)) { + mode &= ALLPERMS; + mode |= S_IFCHR; + } break; case otSymlink: - mode |= S_IFLNK; + if (!S_ISLNK(mode)) { + mode &= ALLPERMS; + mode |= S_IFLNK; + } break; } size_t namelen = strlen(name); - if (ext2_lookup(fs, oid->id, name, namelen, dev, &devOther) > 0) { - if ((obj = ext2_obj_get(fs, dev->id)) == NULL) { + if (ext2_lookup(fs, dir->id, name, namelen, oid, &devOther) > 0) { + if ((obj = ext2_obj_get(fs, oid->id)) == NULL) { return -EINVAL; } mutexLock(obj->lock); - if (S_ISCHR(obj->inode->mode) || S_ISBLK(obj->inode->mode)) { - if (!devOther.port && !devOther.id && (S_ISCHR(mode) || S_ISBLK(mode))) { - memcpy(&obj->dev, res, sizeof(oid_t)); + if (EXT2_ISDEV(obj->inode->mode) && !EXT2_IS_MOUNTPOINT(obj)) { + /* This can happen if we have a device file stored in filesystem + * but no device oid is associated with it at the moment + */ + if (EXT2_ISDEV(mode)) { + memcpy(&obj->dev, dev, sizeof(oid_t)); obj->inode->mode = mode; - obj->flags |= OFLAG_DIRTY; - dev->id = obj->id; + obj->flags |= OFLAG_DIRTY | OFLAG_MOUNTPOINT; + oid->id = obj->id; ret = _ext2_obj_sync(fs, obj); mutexUnlock(obj->lock); @@ -77,12 +91,7 @@ static int libext2_create(void *info, oid_t *oid, const char *name, oid_t *dev, mutexUnlock(obj->lock); ext2_obj_put(fs, obj); - if ((devOther.port == fs->port) && (devOther.id == dev->id)) { - if (ext2_unlink(fs, oid->id, name, namelen) < 0) { - return -EEXIST; - } - } - else { + if (ext2_unlink(fs, dir->id, name, namelen) < 0) { return -EEXIST; } } @@ -94,7 +103,7 @@ static int libext2_create(void *info, oid_t *oid, const char *name, oid_t *dev, } } - ret = ext2_create(fs, oid->id, name, namelen, res, mode, &dev->id); + ret = ext2_create(fs, dir->id, name, namelen, dev, mode, &oid->id); if (ret >= 0 && type == otSymlink) { const char *target = name + namelen + 1; @@ -102,11 +111,11 @@ static int libext2_create(void *info, oid_t *oid, const char *name, oid_t *dev, int retWrite; /* not writing trailing '\0', readlink() does not append it */ - retWrite = ext2_write(fs, dev->id, 0, target, targetlen); + retWrite = ext2_write(fs, oid->id, 0, target, targetlen); if (retWrite < 0) { ret = retWrite; - ext2_destroy(fs, dev->id); - dev->id = 0; + ext2_destroy(fs, oid->id); + oid->id = 0; } } @@ -140,7 +149,7 @@ static ssize_t libext2_write(void *info, oid_t *oid, offs_t offs, const void *da static int libext2_setattr(void *info, oid_t *oid, int type, long long attr, void *data, size_t len) { - return ext2_setattr((ext2_t *)info, oid->id, type, attr); + return ext2_setattr((ext2_t *)info, oid->id, type, attr, data, len); } @@ -168,9 +177,9 @@ static int libext2_lookup(void *info, oid_t *oid, const char *name, oid_t *res, } -static int libext2_link(void *info, oid_t *oid, const char *name, oid_t *res) +static int libext2_link(void *info, oid_t *dir, const char *name, oid_t *oid) { - return ext2_link((ext2_t *)info, oid->id, name, strlen(name), res->id); + return ext2_link((ext2_t *)info, dir->id, name, strlen(name), oid->id); } diff --git a/ext2/obj.c b/ext2/obj.c index 82db1af0..6ecc689f 100644 --- a/ext2/obj.c +++ b/ext2/obj.c @@ -157,20 +157,24 @@ ext2_obj_t *ext2_obj_get(ext2_t *fs, id_t id) ext2_inode_t *inode; mutexLock(fs->objs->lock); - do { tmp.id = id; - if ((obj = lib_treeof(ext2_obj_t, node, lib_rbFind(&fs->objs->used, &tmp.node))) != NULL) { - if (!obj->refs++ && !(S_ISCHR(obj->inode->mode) || S_ISBLK(obj->inode->mode))) + obj = lib_treeof(ext2_obj_t, node, lib_rbFind(&fs->objs->used, &tmp.node)); + if (obj != NULL) { + obj->refs++; + if ((obj->refs == 1) && !EXT2_IS_MOUNTPOINT(obj)) { LIST_REMOVE(&fs->objs->lru, obj); + } break; } - if ((inode = ext2_inode_init(fs, (uint32_t)id)) == NULL) + if ((inode = ext2_inode_init(fs, (uint32_t)id)) == NULL) { break; + } - if (_ext2_obj_create(fs, (uint32_t)id, inode, inode->mode, &obj) < 0) + if (_ext2_obj_create(fs, (uint32_t)id, inode, inode->mode, &obj) < 0) { break; + } } while (0); mutexUnlock(fs->objs->lock); @@ -183,7 +187,8 @@ void ext2_obj_put(ext2_t *fs, ext2_obj_t *obj) { mutexLock(fs->objs->lock); - if (!(--obj->refs) && !(S_ISCHR(obj->inode->mode) || S_ISBLK(obj->inode->mode))) { + obj->refs--; + if ((obj->refs == 0) && !EXT2_IS_MOUNTPOINT(obj)) { if (!obj->inode->links) { _ext2_obj_destroy(fs, obj, false); } @@ -200,14 +205,13 @@ int _ext2_obj_sync(ext2_t *fs, ext2_obj_t *obj) { int err; - if (obj->flags & OFLAG_DIRTY) { + if (EXT2_IS_DIRTY(obj)) { if ((err = ext2_inode_sync(fs, (uint32_t)obj->id, obj->inode)) < 0) return err; obj->flags &= ~OFLAG_DIRTY; } - - if (!(S_ISCHR(obj->inode->mode) || S_ISBLK(obj->inode->mode)) && !(obj->flags & OFLAG_MOUNT)) { + if (!EXT2_ISDEV(obj->inode->mode) && !EXT2_IS_MOUNTPOINT(obj)) { if ((obj->ind[0].data != NULL) && (err = ext2_block_write(fs, obj->ind[0].bno, obj->ind[0].data, 1)) < 0) return err; diff --git a/ext2/obj.h b/ext2/obj.h index b1d4deb6..142c16c2 100644 --- a/ext2/obj.h +++ b/ext2/obj.h @@ -27,25 +27,23 @@ /* Object flags */ enum { - OFLAG_DIRTY = 0x01, + OFLAG_DIRTY = 0x01, OFLAG_MOUNTPOINT = 0x02, - OFLAG_MOUNT = 0x04 }; +#define EXT2_IS_DIRTY(obj) (((obj)->flags & OFLAG_DIRTY) != 0) +#define EXT2_IS_MOUNTPOINT(obj) (((obj)->flags & OFLAG_MOUNTPOINT) != 0) struct _ext2_obj_t { id_t id; /* Object ID, same as underlying inode number */ rbnode_t node; /* RBTree node */ /* Object data */ - union { - struct { - uint32_t bno; - uint32_t *data; - } ind[3]; /* Indirect blocks */ - oid_t mnt; /* Mounted filesystem */ - oid_t dev; /* Device */ - }; + struct { + uint32_t bno; + uint32_t *data; + } ind[3]; /* Indirect blocks */ + oid_t dev; /* Device */ uint32_t refs; /* Reference counter */ uint8_t flags; /* Object flags */ ext2_inode_t *inode; /* Underlying inode */