diff options
Diffstat (limited to 'fs')
84 files changed, 2250 insertions, 1322 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index e0405de334..a3ba84b6ae 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only menu "Filesystem support" @@ -42,6 +43,20 @@ config FS_TFTP prompt "tftp support" depends on NET +config FS_TFTP_MAX_WINDOW_SIZE + int + prompt "maximum tftp window size (RFC 7440)" + depends on FS_TFTP + default 128 + range 1 128 + help + The maximum allowed tftp "windowsize" (RFC 7440). Higher + value increase speed of the tftp download with the cost of + memory (1432 bytes per slot). + + Requires tftp "windowsize" (RFC 7440) support on server side + to have an effect. + config FS_OMAP4_USBBOOT bool prompt "Filesystem over usb boot" @@ -54,7 +69,7 @@ config FS_NFS prompt "nfs support" config FS_EFI - depends on EFI_BOOTUP + depends on EFI_PAYLOAD select FS_LEGACY bool prompt "EFI filesystem support" @@ -63,7 +78,7 @@ config FS_EFI by the EFI Firmware via the EFI Simple File System Protocol. config FS_EFIVARFS - depends on EFI_BOOTUP + depends on EFI_PAYLOAD select FS_LEGACY bool prompt "EFI variable filesystem support (efivarfs)" diff --git a/fs/Makefile b/fs/Makefile index fa950941de..6160ef4e1a 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-$(CONFIG_FS_CRAMFS) += cramfs/ obj-$(CONFIG_FS_EXT4) += ext4/ obj-$(CONFIG_FS_RAMFS) += ramfs.o diff --git a/fs/bpkfs.c b/fs/bpkfs.c index 8fc4df65de..ea2c279585 100644 --- a/fs/bpkfs.c +++ b/fs/bpkfs.c @@ -127,7 +127,7 @@ static struct bpkfs_handle_data *bpkfs_get_by_type( return NULL; } -static int bpkfs_open(struct device_d *dev, FILE *f, const char *filename) +static int bpkfs_open(struct device *dev, FILE *f, const char *filename) { struct bpkfs_handle *priv = dev->priv; struct bpkfs_handle_data *d; @@ -171,7 +171,7 @@ out: return ret; } -static int bpkfs_close(struct device_d *dev, FILE *file) +static int bpkfs_close(struct device *dev, FILE *file) { struct bpkfs_handle_data *d = file->priv; @@ -180,7 +180,8 @@ static int bpkfs_close(struct device_d *dev, FILE *file) return 0; } -static int bpkfs_read(struct device_d *dev, FILE *file, void *buf, size_t insize) +static int bpkfs_read(struct device *dev, FILE *file, void *buf, + size_t insize) { struct bpkfs_handle_data *d = file->priv; @@ -192,7 +193,7 @@ static int bpkfs_read(struct device_d *dev, FILE *file, void *buf, size_t insize } } -static int bpkfs_lseek(struct device_d *dev, FILE *file, loff_t pos) +static int bpkfs_lseek(struct device *dev, FILE *file, loff_t pos) { struct bpkfs_handle_data *d = file->priv; @@ -211,7 +212,7 @@ struct somfy_readdir { DIR dir; }; -static DIR *bpkfs_opendir(struct device_d *dev, const char *pathname) +static DIR *bpkfs_opendir(struct device *dev, const char *pathname) { struct bpkfs_handle *priv = dev->priv; struct somfy_readdir *sdir; @@ -242,7 +243,7 @@ static DIR *bpkfs_opendir(struct device_d *dev, const char *pathname) return dir; } -static struct dirent *bpkfs_readdir(struct device_d *dev, DIR *dir) +static struct dirent *bpkfs_readdir(struct device *dev, DIR *dir) { struct bpkfs_handle *priv = dev->priv; struct somfy_readdir *sdir = dir->priv; @@ -269,7 +270,7 @@ static struct dirent *bpkfs_readdir(struct device_d *dev, DIR *dir) return &dir->d; } -static int bpkfs_closedir(struct device_d *dev, DIR *dir) +static int bpkfs_closedir(struct device *dev, DIR *dir) { struct somfy_readdir *sdir = dir->priv; @@ -277,7 +278,8 @@ static int bpkfs_closedir(struct device_d *dev, DIR *dir) return 0; } -static int bpkfs_stat(struct device_d *dev, const char *filename, struct stat *s) +static int bpkfs_stat(struct device *dev, const char *filename, + struct stat *s) { struct bpkfs_handle *priv = dev->priv; struct bpkfs_handle_data *d; @@ -335,7 +337,7 @@ static void bpkfs_remove_data(struct bpkfs_handle_hw *h) } } -static void bpkfs_remove(struct device_d *dev) +static void bpkfs_remove(struct device *dev) { struct bpkfs_handle *priv = dev->priv; struct bpkfs_handle_hw *h, *tmp; @@ -349,9 +351,9 @@ static void bpkfs_remove(struct device_d *dev) free(priv); } -static int bpkfs_probe(struct device_d *dev) +static int bpkfs_probe(struct device *dev) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct bpkfs_handle *priv; struct bpkfs_header *header; struct bpkfs_data_header data_header; @@ -381,7 +383,7 @@ static int bpkfs_probe(struct device_d *dev) ret = read(fd, header, sizeof(*header)); if (ret < 0) { - dev_err(dev, "could not read: %s (ret = %d)\n", errno_str(), ret); + dev_err(dev, "could not read: %m\n"); goto err; } @@ -407,7 +409,7 @@ static int bpkfs_probe(struct device_d *dev) ret = read(fd, &data_header, sizeof(data_header)); if (ret < 0) { - dev_err(dev, "could not read: %s\n", errno_str()); + dev_err(dev, "could not read: %m\n"); goto err; } else if (ret == 0) { dev_err(dev, "EOF: to_read %llu\n", size); @@ -456,7 +458,7 @@ static int bpkfs_probe(struct device_d *dev) priv->nb_data_entries++; if (lseek(fd, d->size, SEEK_CUR) != d->size) { - dev_err(dev, "could not seek: %s\n", errno_str()); + dev_err(dev, "could not seek: %m\n"); ret = -errno; goto err; } @@ -489,7 +491,7 @@ err: return ret; } -static struct fs_driver_d bpkfs_driver = { +static struct fs_driver bpkfs_driver = { .open = bpkfs_open, .close = bpkfs_close, .read = bpkfs_read, diff --git a/fs/cramfs/Makefile b/fs/cramfs/Makefile index 4e84a98fe1..1b54096664 100644 --- a/fs/cramfs/Makefile +++ b/fs/cramfs/Makefile @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-y += cramfs.o obj-y += uncompress.o diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c index 3ea6bd437e..2d1070f1a7 100644 --- a/fs/cramfs/cramfs.c +++ b/fs/cramfs/cramfs.c @@ -118,7 +118,8 @@ static int cramfs_read_file(struct inode *inode, unsigned long offset, { struct cramfs_inode_info *info = to_cramfs_inode_info(inode); struct cramfs_inode *cramfs_inode = &info->inode; - struct fs_device_d *fsdev = container_of(inode->i_sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(inode->i_sb, struct fs_device, + sb); struct cramfs_priv *priv = fsdev->dev.priv; unsigned int blocknr; int outsize = 0; @@ -161,13 +162,13 @@ static int cramfs_read_file(struct inode *inode, unsigned long offset, return outsize; } -static int cramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size) +static int cramfs_read(struct device *_dev, FILE *f, void *buf, size_t size) { return cramfs_read_file(f->f_inode, f->pos, buf, size); } #if 0 -static int cramfs_info (struct device_d *dev) +static int cramfs_info (struct device *dev) { if (cramfs_read_super (dev)) return 0; @@ -274,7 +275,8 @@ static struct dentry *cramfs_lookup(struct inode *dir, struct dentry *dentry, struct cramfs_inode *de; unsigned int offset = 0; struct inode *inode = NULL; - struct fs_device_d *fsdev = container_of(dir->i_sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(dir->i_sb, struct fs_device, + sb); struct cramfs_priv *priv = fsdev->dev.priv; de = xmalloc(sizeof(*de) + CRAMFS_MAXPATHLEN); @@ -346,7 +348,8 @@ static int cramfs_iterate(struct file *file, struct dir_context *ctx) { struct dentry *dentry = file->f_path.dentry; struct inode *dir = d_inode(dentry); - struct fs_device_d *fsdev = container_of(dir->i_sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(dir->i_sb, struct fs_device, + sb); struct cramfs_priv *priv = fsdev->dev.priv; char *buf; unsigned int offset; @@ -439,9 +442,9 @@ static const struct super_operations cramfs_ops = { .destroy_inode = cramfs_destroy_inode, }; -static int cramfs_probe(struct device_d *dev) +static int cramfs_probe(struct device *dev) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; struct cramfs_priv *priv; int ret; struct super_block *sb; @@ -485,7 +488,7 @@ err_out: return ret; } -static void cramfs_remove(struct device_d *dev) +static void cramfs_remove(struct device *dev) { struct cramfs_priv *priv = dev->priv; @@ -493,7 +496,7 @@ static void cramfs_remove(struct device_d *dev) free(priv); } -static struct fs_driver_d cramfs_driver = { +static struct fs_driver cramfs_driver = { .read = cramfs_read, .drv = { .probe = cramfs_probe, diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c index b7887bd654..82c82adf04 100644 --- a/fs/cramfs/uncompress.c +++ b/fs/cramfs/uncompress.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + /* * uncompress.c * diff --git a/fs/devfs-core.c b/fs/devfs-core.c index f804f96974..376c62be9e 100644 --- a/fs/devfs-core.c +++ b/fs/devfs-core.c @@ -37,8 +37,8 @@ int devfs_partition_complete(struct string_list *sl, char *instr) len = strlen(instr); - list_for_each_entry(cdev, &cdev_list, list) { - if (cdev->master && + for_each_cdev(cdev) { + if (cdev_is_partition(cdev) && !strncmp(instr, cdev->name, len)) { string_list_add_asprintf(sl, "%s ", cdev->name); } @@ -49,6 +49,9 @@ int devfs_partition_complete(struct string_list *sl, char *instr) struct cdev *cdev_readlink(struct cdev *cdev) { + if (!cdev) + return NULL; + if (cdev->link) cdev = cdev->link; @@ -62,7 +65,7 @@ struct cdev *lcdev_by_name(const char *filename) { struct cdev *cdev; - list_for_each_entry(cdev, &cdev_list, list) { + for_each_cdev(cdev) { if (!strcmp(cdev->name, filename)) return cdev; } @@ -84,10 +87,11 @@ struct cdev *cdev_by_device_node(struct device_node *node) { struct cdev *cdev; - list_for_each_entry(cdev, &cdev_list, list) { - if (!cdev->device_node) - continue; - if (cdev->device_node == node) + if (!node) + return NULL; + + for_each_cdev(cdev) { + if (cdev_of_node(cdev) == node) return cdev_readlink(cdev); } return NULL; @@ -100,8 +104,22 @@ struct cdev *cdev_by_partuuid(const char *partuuid) if (!partuuid) return NULL; - list_for_each_entry(cdev, &cdev_list, list) { - if (!strcasecmp(cdev->partuuid, partuuid)) + for_each_cdev(cdev) { + if (cdev_is_partition(cdev) && !strcasecmp(cdev->partuuid, partuuid)) + return cdev; + } + return NULL; +} + +struct cdev *cdev_by_diskuuid(const char *diskuuid) +{ + struct cdev *cdev; + + if (!diskuuid) + return NULL; + + for_each_cdev(cdev) { + if (!cdev_is_partition(cdev) && !strcasecmp(cdev->diskuuid, diskuuid)) return cdev; } return NULL; @@ -113,10 +131,10 @@ struct cdev *cdev_by_partuuid(const char *partuuid) * @dev: the device which should be searched for partitions * @name: the partition name */ -struct cdev *device_find_partition(struct device_d *dev, const char *name) +struct cdev *device_find_partition(struct device *dev, const char *name) { struct cdev *cdev; - struct device_d *child; + struct device *child; list_for_each_entry(cdev, &dev->cdevs, devices_list) { struct cdev *cdevl; @@ -155,7 +173,42 @@ int cdev_find_free_index(const char *basename) return -EBUSY; /* all indexes are used */ } -struct cdev *cdev_open(const char *name, unsigned long flags) +int cdev_open(struct cdev *cdev, unsigned long flags) +{ + int ret; + + if (cdev->ops->open) { + ret = cdev->ops->open(cdev, flags); + if (ret) + return ret; + } + + cdev->open++; + + return 0; +} + +int cdev_fdopen(struct cdev *cdev, unsigned long flags) +{ + char *path; + int fd; + + if (!cdev) + return -ENODEV; + if (IS_ERR(cdev)) + return PTR_ERR(cdev); + + path = basprintf("/dev/%s", cdev->name); + if (!path) + return -ENOMEM; + + fd = open(path, flags); + + free(path); + return fd; +} + +struct cdev *cdev_open_by_name(const char *name, unsigned long flags) { struct cdev *cdev; int ret; @@ -164,11 +217,9 @@ struct cdev *cdev_open(const char *name, unsigned long flags) if (!cdev) return NULL; - if (cdev->ops->open) { - ret = cdev->ops->open(cdev, flags); - if (ret) - return NULL; - } + ret = cdev_open(cdev, flags); + if (ret) + return NULL; return cdev; } @@ -177,6 +228,8 @@ void cdev_close(struct cdev *cdev) { if (cdev->ops->close) cdev->ops->close(cdev); + + cdev->open--; } ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags) @@ -219,6 +272,77 @@ int cdev_erase(struct cdev *cdev, loff_t count, loff_t offset) return cdev->ops->erase(cdev, count, cdev->offset + offset); } +int cdev_lseek(struct cdev *cdev, loff_t pos) +{ + int ret; + + if (cdev->ops->lseek) { + ret = cdev->ops->lseek(cdev, pos + cdev->offset); + if (ret < 0) + return ret; + } + + return 0; +} + +int cdev_protect(struct cdev *cdev, size_t count, loff_t offset, int prot) +{ + if (!cdev->ops->protect) + return -ENOSYS; + + return cdev->ops->protect(cdev, count, offset + cdev->offset, prot); +} + +int cdev_discard_range(struct cdev *cdev, loff_t count, loff_t offset) +{ + if (!cdev->ops->discard_range) + return -ENOSYS; + + if (cdev->flags & DEVFS_PARTITION_READONLY) + return -EPERM; + + if (offset >= cdev->size) + return 0; + + if (count + offset > cdev->size) + count = cdev->size - offset; + + return cdev->ops->discard_range(cdev, count, offset + cdev->offset); +} + +int cdev_memmap(struct cdev *cdev, void **map, int flags) +{ + int ret = -ENOSYS; + + if (!cdev->ops->memmap) + return -EINVAL; + + ret = cdev->ops->memmap(cdev, map, flags); + + if (!ret) + *map = (void *)((unsigned long)*map + (unsigned long)cdev->offset); + + return ret; +} + +int cdev_truncate(struct cdev *cdev, size_t size) +{ + if (cdev->ops->truncate) + return cdev->ops->truncate(cdev, size); + + return -EPERM; +} + +static struct cdev *cdev_alloc(const char *name) +{ + struct cdev *new; + + new = xzalloc(sizeof(*new)); + new->name = xstrdup(name); + + return new; +} + int devfs_create(struct cdev *new) { struct cdev *cdev; @@ -234,7 +358,7 @@ int devfs_create(struct cdev *new) if (new->dev) { list_add_tail(&new->devices_list, &new->dev->cdevs); if (!new->device_node) - new->device_node = new->dev->device_node; + new->device_node = new->dev->of_node; } return 0; @@ -253,8 +377,7 @@ int devfs_create_link(struct cdev *cdev, const char *name) */ cdev = cdev_readlink(cdev); - new = xzalloc(sizeof(*new)); - new->name = xstrdup(name); + new = cdev_alloc(name); new->link = cdev; if (cdev->partname) { @@ -271,6 +394,7 @@ int devfs_create_link(struct cdev *cdev, const char *name) } INIT_LIST_HEAD(&new->links); + INIT_LIST_HEAD(&new->partitions); list_add_tail(&new->list, &cdev_list); list_add_tail(&new->link_entry, &cdev->links); @@ -292,7 +416,10 @@ int devfs_remove(struct cdev *cdev) list_for_each_entry_safe(c, tmp, &cdev->links, link_entry) devfs_remove(c); - if (cdev->master) + list_for_each_entry_safe(c, tmp, &cdev->partitions, partition_entry) + cdevfs_del_partition(c); + + if (cdev_is_partition(cdev)) list_del(&cdev->partition_entry); if (cdev->link) @@ -301,11 +428,82 @@ int devfs_remove(struct cdev *cdev) return 0; } +static bool region_identical(loff_t starta, loff_t lena, + loff_t startb, loff_t lenb) +{ + return starta == startb && lena == lenb; +} + +static bool region_overlap(loff_t starta, loff_t lena, + loff_t startb, loff_t lenb) +{ + if (starta + lena <= startb) + return 0; + if (startb + lenb <= starta) + return 0; + return 1; +} + +/** + * check_overlap() - check overlap with existing partitions + * @cdev: parent cdev + * @name: partition name for informational purposes on conflict + * @offset: offset of new partition to be added + * @size: size of new partition to be added + * + * Return: NULL if no overlapping partition found or overlapping + * partition if and only if it's identical in offset and size + * to an existing partition. Otherwise, PTR_ERR(-EINVAL). + */ +static struct cdev *check_overlap(struct cdev *cdev, const char *name, loff_t offset, loff_t size) +{ + struct cdev *cpart; + loff_t cpart_offset; + int ret; + + list_for_each_entry(cpart, &cdev->partitions, partition_entry) { + cpart_offset = cpart->offset; + + /* + * An mtd partition is represented by a separate cdev and its + * cpart is relative to this one. So its .offset is 0 and we + * have to consult .master_offset to get its offset. + */ + if (cpart->mtd) + cpart_offset = cpart->mtd->master_offset; + + if (region_identical(cpart_offset, cpart->size, offset, size)) { + ret = 0; + goto identical; + } + + if (region_overlap(cpart_offset, cpart->size, offset, size)) { + ret = -EINVAL; + goto conflict; + } + } + + return NULL; + +identical: +conflict: + __pr_printk(ret ? MSG_WARNING : MSG_DEBUG, + "New partition %s (0x%08llx-0x%08llx) on %s " + "%s with partition %s (0x%08llx-0x%08llx), not creating it\n", + name, offset, offset + size - 1, cdev->name, + ret ? "conflicts" : "identical", + cpart->name, cpart_offset, cpart_offset + cpart->size - 1); + + return ret ? ERR_PTR(ret) : cpart; +} + static struct cdev *__devfs_add_partition(struct cdev *cdev, const struct devfs_partition *partinfo, loff_t *end) { loff_t offset, size; + loff_t _end = end ? *end : 0; static struct cdev *new; + struct cdev *overlap; if (cdev_by_name(partinfo->name)) return ERR_PTR(-EEXIST); @@ -314,7 +512,7 @@ static struct cdev *__devfs_add_partition(struct cdev *cdev, offset = partinfo->offset; else if (partinfo->offset == 0) /* append to previous partition */ - offset = *end; + offset = _end; else /* relative to end of cdev */ offset = cdev->size + partinfo->offset; @@ -324,18 +522,30 @@ static struct cdev *__devfs_add_partition(struct cdev *cdev, else size = cdev->size + partinfo->size - offset; - if (offset >= 0 && offset < *end) + if (offset >= 0 && offset < _end) pr_debug("partition %s not after previous partition\n", partinfo->name); - *end = offset + size; + _end = offset + size; + if (end) + *end = _end; - if (offset < 0 || *end > cdev->size) { + if (offset < 0 || _end > cdev->size) { pr_warn("partition %s not completely inside device %s\n", partinfo->name, cdev->name); return ERR_PTR(-EINVAL); } + overlap = check_overlap(cdev, partinfo->name, offset, size); + if (overlap) { + if (!IS_ERR(overlap)) { + /* only fails with -EEXIST, which is fine */ + (void)devfs_create_link(overlap, partinfo->name); + } + + return overlap; + } + if (IS_ENABLED(CONFIG_MTD) && cdev->mtd) { struct mtd_info *mtd; @@ -348,8 +558,7 @@ static struct cdev *__devfs_add_partition(struct cdev *cdev, return &mtd->cdev; } - new = xzalloc(sizeof(*new)); - new->name = strdup(partinfo->name); + new = cdev_alloc(partinfo->name); if (!strncmp(cdev->name, partinfo->name, strlen(cdev->name))) new->partname = xstrdup(partinfo->name + strlen(cdev->name) + 1); @@ -370,11 +579,16 @@ static struct cdev *__devfs_add_partition(struct cdev *cdev, return new; } +struct cdev *cdevfs_add_partition(struct cdev *cdev, + const struct devfs_partition *partinfo) +{ + return __devfs_add_partition(cdev, partinfo, NULL); +} + struct cdev *devfs_add_partition(const char *devname, loff_t offset, loff_t size, unsigned int flags, const char *name) { struct cdev *cdev; - loff_t end = 0; const struct devfs_partition partinfo = { .offset = offset, .size = size, @@ -386,28 +600,21 @@ struct cdev *devfs_add_partition(const char *devname, loff_t offset, if (!cdev) return ERR_PTR(-ENOENT); - return __devfs_add_partition(cdev, &partinfo, &end); + return cdevfs_add_partition(cdev, &partinfo); } -int devfs_del_partition(const char *name) +int cdevfs_del_partition(struct cdev *cdev) { - struct cdev *cdev; int ret; - cdev = cdev_by_name(name); - if (!cdev) - return -ENOENT; + if (cdev->flags & DEVFS_PARTITION_FIXED) + return -EPERM; if (IS_ENABLED(CONFIG_MTD) && cdev->mtd) { ret = mtd_del_partition(cdev->mtd); return ret; } - if (!cdev->master) - return -EINVAL; - if (cdev->flags & DEVFS_PARTITION_FIXED) - return -EPERM; - ret = devfs_remove(cdev); if (ret) return ret; @@ -419,6 +626,20 @@ int devfs_del_partition(const char *name) return 0; } +int devfs_del_partition(const char *name) +{ + struct cdev *cdev; + + cdev = cdev_by_name(name); + if (!cdev) + return -ENOENT; + + if (!cdev_is_partition(cdev)) + return -EINVAL; + + return cdevfs_del_partition(cdev); +} + int devfs_create_partitions(const char *devname, const struct devfs_partition partinfo[]) { @@ -481,6 +702,7 @@ static const struct cdev_operations loop_ops = { struct cdev *cdev_create_loop(const char *path, ulong flags, loff_t offset) { + char str[16]; struct cdev *new; struct loop_priv *priv; static int loopno; @@ -494,10 +716,10 @@ struct cdev *cdev_create_loop(const char *path, ulong flags, loff_t offset) return NULL; } - new = xzalloc(sizeof(*new)); + snprintf(str, sizeof(str), "loop%u", loopno++); + new = cdev_alloc(str); new->ops = &loop_ops; - new->name = basprintf("loop%u", loopno++); new->priv = priv; ofs = lseek(priv->fd, 0, SEEK_END); @@ -529,7 +751,7 @@ void cdev_remove_loop(struct cdev *cdev) free(cdev); } -static ssize_t mem_copy(struct device_d *dev, void *dst, const void *src, +ssize_t mem_copy(struct device *dev, void *dst, const void *src, resource_size_t count, resource_size_t offset, unsigned long flags) { @@ -539,7 +761,10 @@ static ssize_t mem_copy(struct device_d *dev, void *dst, const void *src, if (!dev || dev->num_resources < 1) return -1; - count = size = min(count, resource_size(&dev->resource[0]) - offset); + if (resource_size(&dev->resource[0]) > 0 || offset != 0) + count = min(count, resource_size(&dev->resource[0]) - offset); + + size = count; /* no rwsize specification given. Do whatever memcpy likes best */ if (!rwsize) { @@ -577,7 +802,7 @@ out: ssize_t mem_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, unsigned long flags) { - struct device_d *dev = cdev->dev; + struct device *dev = cdev->dev; if (!dev) return -1; @@ -590,7 +815,7 @@ EXPORT_SYMBOL(mem_read); ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, unsigned long flags) { - struct device_d *dev = cdev->dev; + struct device *dev = cdev->dev; if (!dev) return -1; diff --git a/fs/devfs.c b/fs/devfs.c index df229cca48..c8ddbbdab0 100644 --- a/fs/devfs.c +++ b/fs/devfs.c @@ -28,23 +28,22 @@ #include <linux/err.h> #include <linux/mtd/mtd.h> #include <linux/mtd/mtd-abi.h> -#include <partition.h> +#include <block.h> struct devfs_inode { struct inode inode; struct cdev *cdev; }; -extern struct list_head cdev_list; - -static int devfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size) +static int devfs_read(struct device *_dev, FILE *f, void *buf, size_t size) { struct cdev *cdev = f->priv; return cdev_read(cdev, buf, size, f->pos, f->flags); } -static int devfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t size) +static int devfs_write(struct device *_dev, FILE *f, const void *buf, + size_t size) { struct cdev *cdev = f->priv; @@ -54,21 +53,15 @@ static int devfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t s return cdev_write(cdev, buf, size, f->pos, f->flags); } -static int devfs_lseek(struct device_d *_dev, FILE *f, loff_t pos) +static int devfs_lseek(struct device *_dev, FILE *f, loff_t pos) { struct cdev *cdev = f->priv; - int ret; - - if (cdev->ops->lseek) { - ret = cdev->ops->lseek(cdev, pos + cdev->offset); - if (ret < 0) - return ret; - } - return 0; + return cdev_lseek(cdev, pos); } -static int devfs_erase(struct device_d *_dev, FILE *f, loff_t count, loff_t offset) +static int devfs_erase(struct device *_dev, FILE *f, loff_t count, + loff_t offset) { struct cdev *cdev = f->priv; @@ -81,53 +74,30 @@ static int devfs_erase(struct device_d *_dev, FILE *f, loff_t count, loff_t offs return cdev_erase(cdev, count, offset); } -static int devfs_protect(struct device_d *_dev, FILE *f, size_t count, loff_t offset, int prot) +static int devfs_protect(struct device *dev, FILE *f, size_t count, + loff_t offset, int prot) { struct cdev *cdev = f->priv; - if (!cdev->ops->protect) - return -ENOSYS; - - return cdev->ops->protect(cdev, count, offset + cdev->offset, prot); + return cdev_protect(cdev, count, offset, prot); } -static int devfs_discard_range(struct device_d *dev, FILE *f, loff_t count, +static int devfs_discard_range(struct device *dev, FILE *f, loff_t count, loff_t offset) { struct cdev *cdev = f->priv; - if (!cdev->ops->discard_range) - return -ENOSYS; - - if (cdev->flags & DEVFS_PARTITION_READONLY) - return -EPERM; - - if (offset >= cdev->size) - return 0; - - if (count + offset > cdev->size) - count = cdev->size - offset; - - return cdev->ops->discard_range(cdev, count, offset + cdev->offset); + return cdev_discard_range(cdev, count, offset); } -static int devfs_memmap(struct device_d *_dev, FILE *f, void **map, int flags) +static int devfs_memmap(struct device *_dev, FILE *f, void **map, int flags) { struct cdev *cdev = f->priv; - int ret = -ENOSYS; - - if (!cdev->ops->memmap) - return -EINVAL; - - ret = cdev->ops->memmap(cdev, map, flags); - if (!ret) - *map = (void *)((unsigned long)*map + (unsigned long)cdev->offset); - - return ret; + return cdev_memmap(cdev, map, flags); } -static int devfs_open(struct device_d *_dev, FILE *f, const char *filename) +static int devfs_open(struct device *_dev, FILE *f, const char *filename) { struct inode *inode = f->f_inode; struct devfs_inode *node = container_of(inode, struct devfs_inode, inode); @@ -144,12 +114,10 @@ static int devfs_open(struct device_d *_dev, FILE *f, const char *filename) return ret; } - cdev->open++; - return 0; } -static int devfs_close(struct device_d *_dev, FILE *f) +static int devfs_close(struct device *_dev, FILE *f) { struct cdev *cdev = f->priv; int ret; @@ -160,33 +128,28 @@ static int devfs_close(struct device_d *_dev, FILE *f) return ret; } - cdev->open--; - return 0; } -static int devfs_flush(struct device_d *_dev, FILE *f) +static int devfs_flush(struct device *_dev, FILE *f) { struct cdev *cdev = f->priv; return cdev_flush(cdev); } -static int devfs_ioctl(struct device_d *_dev, FILE *f, int request, void *buf) +static int devfs_ioctl(struct device *_dev, FILE *f, int request, void *buf) { struct cdev *cdev = f->priv; return cdev_ioctl(cdev, request, buf); } -static int devfs_truncate(struct device_d *dev, FILE *f, loff_t size) +static int devfs_truncate(struct device *dev, FILE *f, loff_t size) { struct cdev *cdev = f->priv; - if (cdev->ops->truncate) - return cdev->ops->truncate(cdev, size); - - return -EPERM; + return cdev_truncate(cdev, size); } static struct inode *devfs_alloc_inode(struct super_block *sb) @@ -213,7 +176,7 @@ static int devfs_iterate(struct file *file, struct dir_context *ctx) dir_emit_dots(file, ctx); - list_for_each_entry(cdev, &cdev_list, list) { + for_each_cdev(cdev) { dir_emit(ctx, cdev->name, strlen(cdev->name), 1 /* FIXME */, DT_REG); } @@ -267,6 +230,7 @@ static struct inode *devfs_get_inode(struct super_block *sb, const struct inode default: return NULL; case S_IFCHR: + case S_IFBLK: inode->i_op = &devfs_file_inode_operations; inode->i_fop = &devfs_file_operations; break; @@ -286,12 +250,15 @@ static struct dentry *devfs_lookup(struct inode *dir, struct dentry *dentry, struct devfs_inode *dinode; struct inode *inode; struct cdev *cdev; + umode_t mode; cdev = cdev_by_name(dentry->name); if (!cdev) return ERR_PTR(-ENOENT); - inode = devfs_get_inode(dir->i_sb, dir, S_IFCHR); + mode = cdev_get_block_device(cdev) ? S_IFBLK : S_IFCHR; + + inode = devfs_get_inode(dir->i_sb, dir, mode); if (!inode) return ERR_PTR(-ENOMEM); @@ -324,10 +291,10 @@ static const struct super_operations devfs_ops = { .destroy_inode = devfs_destroy_inode, }; -static int devfs_probe(struct device_d *dev) +static int devfs_probe(struct device *dev) { struct inode *inode; - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct super_block *sb = &fsdev->sb; sb->s_op = &devfs_ops; @@ -339,11 +306,11 @@ static int devfs_probe(struct device_d *dev) return 0; } -static void devfs_delete(struct device_d *dev) +static void devfs_delete(struct device *dev) { } -static struct fs_driver_d devfs_driver = { +static struct fs_driver devfs_driver = { .read = devfs_read, .write = devfs_write, .lseek = devfs_lseek, @@ -28,69 +28,10 @@ #include <wchar.h> #include <efi.h> #include <libfile.h> -#include <efi/efi.h> +#include <efi/efi-payload.h> #include <efi/efi-device.h> #include <linux/stddef.h> -/* Open modes */ -#define EFI_FILE_MODE_READ 0x0000000000000001 -#define EFI_FILE_MODE_WRITE 0x0000000000000002 -#define EFI_FILE_MODE_CREATE 0x8000000000000000 - -/* File attributes */ -#define EFI_FILE_READ_ONLY 0x0000000000000001 -#define EFI_FILE_HIDDEN 0x0000000000000002 -#define EFI_FILE_SYSTEM 0x0000000000000004 -#define EFI_FILE_RESERVIED 0x0000000000000008 -#define EFI_FILE_DIRECTORY 0x0000000000000010 -#define EFI_FILE_ARCHIVE 0x0000000000000020 -#define EFI_FILE_VALID_ATTR 0x0000000000000037 - -#define EFI_FILE_HANDLE_REVISION 0x00010000 -struct efi_file_handle { - uint64_t Revision; - efi_status_t(EFIAPI *open)(struct efi_file_handle *File, - struct efi_file_handle **NewHandle, s16 *FileName, - uint64_t OpenMode, uint64_t Attributes); - efi_status_t(EFIAPI *close)(struct efi_file_handle *File); - efi_status_t(EFIAPI *delete)(struct efi_file_handle *File); - efi_status_t(EFIAPI *read)(struct efi_file_handle *File, unsigned long *BufferSize, - void *Buffer); - efi_status_t(EFIAPI *write)(struct efi_file_handle *File, - unsigned long *BufferSize, void *Buffer); - efi_status_t(EFIAPI *get_position)(struct efi_file_handle *File, - uint64_t *Position); - efi_status_t(EFIAPI *set_position)(struct efi_file_handle *File, - uint64_t Position); - efi_status_t(EFIAPI *get_info)(struct efi_file_handle *File, - efi_guid_t *InformationType, unsigned long *BufferSize, - void *Buffer); - efi_status_t(EFIAPI *set_info)(struct efi_file_handle *File, - efi_guid_t *InformationType, unsigned long BufferSize, - void *Buffer); - efi_status_t(EFIAPI *flush)(struct efi_file_handle *File); -}; - -#define EFI_FILE_IO_INTERFACE_REVISION 0x00010000 - -struct efi_file_io_interface { - uint64_t Revision; - efi_status_t(EFIAPI *open_volume)( - struct efi_file_io_interface *This, - struct efi_file_handle **Root); -}; - -struct efi_file_info { - uint64_t Size; - uint64_t FileSize; - uint64_t PhysicalSize; - efi_time_t CreateTime; - efi_time_t LastAccessTime; - efi_time_t ModificationTime; - uint64_t Attribute; - s16 FileName[1]; -}; - struct efifs_priv { struct efi_file_handle *root_dir; struct efi_file_io_interface *protocol; @@ -128,7 +69,7 @@ static wchar_t *path_to_efi(const char *path) return ret; } -static int efifs_create(struct device_d *dev, const char *pathname, mode_t mode) +static int efifs_create(struct device *dev, const char *pathname, mode_t mode) { struct efifs_priv *priv = dev->priv; wchar_t *efi_path = path_to_efi(pathname); @@ -151,7 +92,7 @@ static int efifs_create(struct device_d *dev, const char *pathname, mode_t mode) return 0; } -static int efifs_unlink(struct device_d *dev, const char *pathname) +static int efifs_unlink(struct device *dev, const char *pathname) { struct efifs_priv *priv = dev->priv; wchar_t *efi_path = path_to_efi(pathname); @@ -173,7 +114,7 @@ static int efifs_unlink(struct device_d *dev, const char *pathname) return 0; } -static int efifs_mkdir(struct device_d *dev, const char *pathname) +static int efifs_mkdir(struct device *dev, const char *pathname) { struct efifs_priv *priv = dev->priv; wchar_t *efi_path = path_to_efi(pathname); @@ -196,12 +137,12 @@ static int efifs_mkdir(struct device_d *dev, const char *pathname) return 0; } -static int efifs_rmdir(struct device_d *dev, const char *pathname) +static int efifs_rmdir(struct device *dev, const char *pathname) { return efifs_unlink(dev, pathname); } -static int efifs_open(struct device_d *dev, FILE *f, const char *filename) +static int efifs_open(struct device *dev, FILE *f, const char *filename) { struct efifs_priv *priv = dev->priv; efi_status_t efiret; @@ -249,7 +190,7 @@ out: return ret; } -static int efifs_close(struct device_d *dev, FILE *f) +static int efifs_close(struct device *dev, FILE *f) { struct efifs_file *ufile = f->priv; @@ -260,7 +201,7 @@ static int efifs_close(struct device_d *dev, FILE *f) return 0; } -static int efifs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) +static int efifs_read(struct device *_dev, FILE *f, void *buf, size_t insize) { struct efifs_file *ufile = f->priv; efi_status_t efiret; @@ -274,7 +215,8 @@ static int efifs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) return bufsize; } -static int efifs_write(struct device_d *_dev, FILE *f, const void *buf, size_t insize) +static int efifs_write(struct device *_dev, FILE *f, const void *buf, + size_t insize) { struct efifs_file *ufile = f->priv; efi_status_t efiret; @@ -289,7 +231,7 @@ static int efifs_write(struct device_d *_dev, FILE *f, const void *buf, size_t i return bufsize; } -static int efifs_lseek(struct device_d *dev, FILE *f, loff_t pos) +static int efifs_lseek(struct device *dev, FILE *f, loff_t pos) { struct efifs_file *ufile = f->priv; efi_status_t efiret; @@ -302,7 +244,7 @@ static int efifs_lseek(struct device_d *dev, FILE *f, loff_t pos) return 0; } -static int efifs_truncate(struct device_d *dev, FILE *f, loff_t size) +static int efifs_truncate(struct device *dev, FILE *f, loff_t size) { struct efifs_file *ufile = f->priv; efi_status_t efiret; @@ -336,7 +278,7 @@ out: return ret; } -static DIR *efifs_opendir(struct device_d *dev, const char *pathname) +static DIR *efifs_opendir(struct device *dev, const char *pathname) { struct efifs_priv *priv = dev->priv; efi_status_t efiret; @@ -356,7 +298,7 @@ static DIR *efifs_opendir(struct device_d *dev, const char *pathname) return &udir->dir; } -static struct dirent *efifs_readdir(struct device_d *dev, DIR *dir) +static struct dirent *efifs_readdir(struct device *dev, DIR *dir) { struct efifs_dir *udir = container_of(dir, struct efifs_dir, dir); efi_status_t efiret; @@ -375,7 +317,7 @@ static struct dirent *efifs_readdir(struct device_d *dev, DIR *dir) return &dir->d; } -static int efifs_closedir(struct device_d *dev, DIR *dir) +static int efifs_closedir(struct device *dev, DIR *dir) { struct efifs_dir *udir = container_of(dir, struct efifs_dir, dir); @@ -386,7 +328,8 @@ static int efifs_closedir(struct device_d *dev, DIR *dir) return 0; } -static int efifs_stat(struct device_d *dev, const char *filename, struct stat *s) +static int efifs_stat(struct device *dev, const char *filename, + struct stat *s) { struct efifs_priv *priv = dev->priv; wchar_t *efi_path; @@ -435,25 +378,25 @@ out_free: return ret; } -static int efifs_symlink(struct device_d *dev, const char *pathname, - const char *newpath) +static int efifs_symlink(struct device *dev, const char *pathname, + const char *newpath) { return -EROFS; } -static int efifs_readlink(struct device_d *dev, const char *pathname, - char *buf, size_t bufsiz) +static int efifs_readlink(struct device *dev, const char *pathname, + char *buf, size_t bufsiz) { return -ENOENT; } -static int efifs_probe(struct device_d *dev) +static int efifs_probe(struct device *dev) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct efifs_priv *priv; efi_status_t efiret; struct efi_file_handle *file; - struct device_d *efi = get_device_by_name(fsdev->backingstore); + struct device *efi = get_device_by_name(fsdev->backingstore); struct efi_device *udev = container_of(efi, struct efi_device, dev); priv = xzalloc(sizeof(struct efifs_priv)); @@ -472,12 +415,12 @@ static int efifs_probe(struct device_d *dev) return 0; } -static void efifs_remove(struct device_d *dev) +static void efifs_remove(struct device *dev) { free(dev->priv); } -static struct fs_driver_d efifs_driver = { +static struct fs_driver efifs_driver = { .create = efifs_create, .unlink = efifs_unlink, .open = efifs_open, diff --git a/fs/efivarfs.c b/fs/efivarfs.c index 659716f845..b199318061 100644 --- a/fs/efivarfs.c +++ b/fs/efivarfs.c @@ -28,7 +28,7 @@ #include <wchar.h> #include <linux/err.h> #include <linux/ctype.h> -#include <efi/efi.h> +#include <efi/efi-payload.h> #include <efi/efi-device.h> struct efivarfs_inode { @@ -47,83 +47,8 @@ struct efivarfs_priv { struct list_head inodes; }; -static int char_to_nibble(char c) -{ - int ret = tolower(c); - - return ret <= '9' ? ret - '0' : ret - 'a' + 10; -} - -static int read_byte_str(const char *str, u8 *out) -{ - if (!isxdigit(*str) || !isxdigit(*(str + 1))) - return -EINVAL; - - *out = (char_to_nibble(*str) << 4) | char_to_nibble(*(str + 1)); - - return 0; -} - -static int efi_guid_parse(const char *str, efi_guid_t *guid) -{ - int i, ret; - u8 idx[] = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 }; - - for (i = 0; i < 16; i++) { - ret = read_byte_str(str, &guid->b[idx[i]]); - if (ret) - return ret; - str += 2; - - switch (i) { - case 3: - case 5: - case 7: - case 9: - if (*str != '-') - return -EINVAL; - str++; - break; - } - } - - return 0; -} - -static int efivarfs_parse_filename(const char *filename, efi_guid_t *vendor, s16 **name) -{ - int len, ret; - const char *guidstr; - s16 *varname; - int i; - - if (*filename == '/') - filename++; - - len = strlen(filename); - - if (len < sizeof("-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")) - return -EINVAL; - - guidstr = filename + len - sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); - if (*guidstr != '-') - return -EINVAL; - - guidstr++; - - ret = efi_guid_parse(guidstr, vendor); - - varname = xzalloc((guidstr - filename) * sizeof(s16)); - - for (i = 0; i < guidstr - filename - 1; i++) - varname[i] = filename[i]; - - *name = varname; - - return 0; -} - -static int efivars_create(struct device_d *dev, const char *pathname, mode_t mode) +static int efivars_create(struct device *dev, const char *pathname, + mode_t mode) { struct efivarfs_priv *priv = dev->priv; struct efivarfs_inode *inode; @@ -169,7 +94,7 @@ static int efivars_create(struct device_d *dev, const char *pathname, mode_t mod return 0; } -static int efivars_unlink(struct device_d *dev, const char *pathname) +static int efivars_unlink(struct device *dev, const char *pathname) { struct efivarfs_priv *priv = dev->priv; struct efivarfs_inode *inode, *tmp; @@ -200,7 +125,7 @@ struct efivars_file { u32 attributes; }; -static int efivarfs_open(struct device_d *dev, FILE *f, const char *filename) +static int efivarfs_open(struct device *dev, FILE *f, const char *filename) { struct efivars_file *efile; efi_status_t efiret; @@ -245,7 +170,7 @@ out: return ret; } -static int efivarfs_close(struct device_d *dev, FILE *f) +static int efivarfs_close(struct device *dev, FILE *f) { struct efivars_file *efile = f->priv; @@ -255,7 +180,8 @@ static int efivarfs_close(struct device_d *dev, FILE *f) return 0; } -static int efivarfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) +static int efivarfs_read(struct device *_dev, FILE *f, void *buf, + size_t insize) { struct efivars_file *efile = f->priv; @@ -264,7 +190,8 @@ static int efivarfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insiz return insize; } -static int efivarfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t insize) +static int efivarfs_write(struct device *_dev, FILE *f, const void *buf, + size_t insize) { struct efivars_file *efile = f->priv; efi_status_t efiret; @@ -285,7 +212,7 @@ static int efivarfs_write(struct device_d *_dev, FILE *f, const void *buf, size_ return insize; } -static int efivarfs_truncate(struct device_d *dev, FILE *f, loff_t size) +static int efivarfs_truncate(struct device *dev, FILE *f, loff_t size) { struct efivars_file *efile = f->priv; efi_status_t efiret; @@ -304,7 +231,7 @@ static int efivarfs_truncate(struct device_d *dev, FILE *f, loff_t size) return 0; } -static DIR *efivarfs_opendir(struct device_d *dev, const char *pathname) +static DIR *efivarfs_opendir(struct device *dev, const char *pathname) { struct efivarfs_priv *priv = dev->priv; struct efivarfs_dir *edir; @@ -315,7 +242,7 @@ static DIR *efivarfs_opendir(struct device_d *dev, const char *pathname) return &edir->dir; } -static struct dirent *efivarfs_readdir(struct device_d *dev, DIR *dir) +static struct dirent *efivarfs_readdir(struct device *dev, DIR *dir) { struct efivarfs_priv *priv = dev->priv; struct efivarfs_dir *edir = container_of(dir, struct efivarfs_dir, dir); @@ -333,7 +260,7 @@ static struct dirent *efivarfs_readdir(struct device_d *dev, DIR *dir) return &dir->d; } -static int efivarfs_closedir(struct device_d *dev, DIR *dir) +static int efivarfs_closedir(struct device *dev, DIR *dir) { struct efivarfs_dir *edir = container_of(dir, struct efivarfs_dir, dir); @@ -342,7 +269,8 @@ static int efivarfs_closedir(struct device_d *dev, DIR *dir) return 0; } -static int efivarfs_stat(struct device_d *dev, const char *filename, struct stat *s) +static int efivarfs_stat(struct device *dev, const char *filename, + struct stat *s) { efi_guid_t vendor; s16 *name; @@ -367,7 +295,7 @@ static int efivarfs_stat(struct device_d *dev, const char *filename, struct stat return 0; } -static int efivarfs_probe(struct device_d *dev) +static int efivarfs_probe(struct device *dev) { efi_status_t efiret; efi_guid_t vendor; @@ -406,7 +334,7 @@ static int efivarfs_probe(struct device_d *dev) return 0; } -static void efivarfs_remove(struct device_d *dev) +static void efivarfs_remove(struct device *dev) { struct efivarfs_priv *priv = dev->priv; struct efivarfs_inode *inode, *tmp; @@ -419,7 +347,7 @@ static void efivarfs_remove(struct device_d *dev) free(priv); } -static struct fs_driver_d efivarfs_driver = { +static struct fs_driver efivarfs_driver = { .create = efivars_create, .unlink = efivars_unlink, .open = efivarfs_open, @@ -443,4 +371,4 @@ static int efivarfs_init(void) return register_fs_driver(&efivarfs_driver); } -coredevice_initcall(efivarfs_init); +coredevice_efi_initcall(efivarfs_init); diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index f36043d9a7..cb01675507 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + config FS_EXT4 bool prompt "ext4 filesystem support" diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 5084e3fb25..223f50e470 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -1 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-$(CONFIG_FS_EXT4) += ext4fs.o ext4_common.o ext_barebox.o diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index c9f27f1278..4bfb55ad0d 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -43,10 +43,11 @@ static struct ext4_extent_header *ext4fs_get_extent_block(struct ext2_data *data uint32_t fileblock, int log2_blksz) { struct ext4_extent_idx *index; - unsigned long long block; + sector_t block; struct ext_filesystem *fs = data->fs; int blksz = EXT2_BLOCK_SIZE(data); - int i, ret; + ssize_t ret; + int i; while (1) { index = (struct ext4_extent_idx *)(ext_block + 1); @@ -77,10 +78,10 @@ static struct ext4_extent_header *ext4fs_get_extent_block(struct ext2_data *data } } -static int ext4fs_blockgroup(struct ext2_data *data, int group, +static ssize_t ext4fs_blockgroup(struct ext2_data *data, int group, struct ext2_block_group *blkgrp) { - long int blkno; + sector_t blkno; unsigned int blkoff, desc_per_blk; struct ext_filesystem *fs = data->fs; int desc_size = fs->gdsize; @@ -91,7 +92,7 @@ static int ext4fs_blockgroup(struct ext2_data *data, int group, group / desc_per_blk; blkoff = (group % desc_per_blk) * desc_size; - dev_dbg(fs->dev, "read %d group descriptor (blkno %ld blkoff %u)\n", + dev_dbg(fs->dev, "read %d group descriptor (blkno %llu blkoff %u)\n", group, blkno, blkoff); return ext4fs_devread(fs, blkno << LOG2_EXT2_BLOCK_SIZE(data), @@ -103,8 +104,9 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) struct ext2_block_group blkgrp; struct ext2_sblock *sblock = &data->sblock; struct ext_filesystem *fs = data->fs; - int inodes_per_block, ret; - long int blkno; + int inodes_per_block; + ssize_t ret; + sector_t blkno; unsigned int blkoff; /* It is easier to calculate if the first inode is 0. */ @@ -128,11 +130,11 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) } static int ext4fs_get_indir_block(struct ext2fs_node *node, - struct ext4fs_indir_block *indir, int blkno) + struct ext4fs_indir_block *indir, sector_t blkno) { struct ext_filesystem *fs = node->data->fs; int blksz; - int ret; + ssize_t ret; blksz = EXT2_BLOCK_SIZE(node->data); @@ -488,7 +490,8 @@ fail: int ext4fs_mount(struct ext_filesystem *fs) { struct ext2_data *data; - int ret, blksz; + ssize_t ret; + int blksz; data = zalloc(sizeof(struct ext2_data)); if (!data) diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h index 81fb67ef4c..f8ebd76266 100644 --- a/fs/ext4/ext4_common.h +++ b/fs/ext4/ext4_common.h @@ -48,8 +48,8 @@ static inline void *zalloc(size_t size) int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode); -int ext4fs_read_file(struct ext2fs_node *node, int pos, - unsigned int len, char *buf); +loff_t ext4fs_read_file(struct ext2fs_node *node, loff_t pos, + unsigned int len, char *buf); int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode, struct ext2fs_node **foundnode, int *foundtype); int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c index 2d231d273a..344d423fd9 100644 --- a/fs/ext4/ext4fs.c +++ b/fs/ext4/ext4fs.c @@ -47,38 +47,42 @@ void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot) * Optimized read file API : collects and defers contiguous sector * reads into one potentially more efficient larger sequential read action */ -int ext4fs_read_file(struct ext2fs_node *node, int pos, +loff_t ext4fs_read_file(struct ext2fs_node *node, loff_t pos, unsigned int len, char *buf) { - int i; - int blockcnt; + loff_t i; + blkcnt_t blockcnt; int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data); - int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS); - unsigned int filesize = le32_to_cpu(node->inode.size); - short ret; + const int blockshift = log2blocksize + DISK_SECTOR_BITS; + const int blocksize = 1 << blockshift; + loff_t filesize = ext4_isize(node); + ssize_t ret; struct ext_filesystem *fs = node->data->fs; /* Adjust len so it we can't read past the end of the file. */ - if (len > filesize) - len = filesize; + if (len + pos > filesize) + len = filesize - pos; - blockcnt = ((len + pos) + blocksize - 1) / blocksize; + if (filesize <= pos) + return -EINVAL; - for (i = pos / blocksize; i < blockcnt; i++) { - int blknr; - int blockoff = pos % blocksize; - int blockend = blocksize; - int skipfirst = 0; + blockcnt = ((len + pos) + blocksize - 1) >> blockshift; - blknr = read_allocated_block(node, i); - if (blknr < 0) - return blknr; + for (i = pos >> blockshift; i < blockcnt; i++) { + sector_t blknr; + loff_t blockoff = pos - (blocksize * i); + loff_t blockend = blocksize; + loff_t skipfirst = 0; - blknr = blknr << log2blocksize; + ret = read_allocated_block(node, i); + if (ret < 0) + return ret; + + blknr = ret << log2blocksize; /* Last block. */ if (i == blockcnt - 1) { - blockend = (len + pos) % blocksize; + blockend = (len + pos) - (blocksize * i); /* The last portion is exactly blocksize. */ if (!blockend) @@ -86,7 +90,7 @@ int ext4fs_read_file(struct ext2fs_node *node, int pos, } /* First block. */ - if (i == pos / blocksize) { + if (i == pos >> blockshift) { skipfirst = blockoff; blockend -= skipfirst; } diff --git a/fs/ext4/ext4fs.h b/fs/ext4/ext4fs.h index 17a490a943..707565e671 100644 --- a/fs/ext4/ext4fs.h +++ b/fs/ext4/ext4fs.h @@ -74,46 +74,17 @@ struct ext4_extent_header { }; struct ext_filesystem { - /* Total Sector of partition */ - uint64_t total_sect; - /* Block size of partition */ - uint32_t blksz; /* Inode size of partition */ uint32_t inodesz; - /* Sectors per Block */ - uint32_t sect_perblk; /* Group Descriptor size */ uint16_t gdsize; - /* Group Descriptor Block Number */ - uint32_t gdtable_blkno; - /* Total block groups of partition */ - uint32_t no_blkgrp; - /* No of blocks required for bgdtable */ - uint32_t no_blk_pergdt; - /* Superblock */ - struct ext2_sblock *sb; - /* Block group descritpor table */ - struct ext2_block_group *bgd; - char *gdtable; - - /* Block Bitmap Related */ - unsigned char **blk_bmaps; - long int curr_blkno; - uint16_t first_pass_bbmap; - - /* Inode Bitmap Related */ - unsigned char **inode_bmaps; - int curr_inode_no; - uint16_t first_pass_ibmap; - - /* Journal Related */ /* Block Device Descriptor */ struct cdev *cdev; struct ext2_data *data; - struct device_d *dev; + struct device *dev; }; struct ext2fs_node; @@ -124,7 +95,7 @@ int ext4fs_mount(struct ext_filesystem *fs); void ext4fs_umount(struct ext_filesystem *fs); char *ext4fs_read_symlink(struct ext2fs_node *node); void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot); -int ext4fs_devread(struct ext_filesystem *fs, int sector, int byte_offset, int byte_len, char *buf); +ssize_t ext4fs_devread(struct ext_filesystem *fs, sector_t sector, int byte_offset, size_t byte_len, char *buf); long int read_allocated_block(struct ext2fs_node *node, int fileblock); #endif diff --git a/fs/ext4/ext_barebox.c b/fs/ext4/ext_barebox.c index 353ab44b29..df82b629cd 100644 --- a/fs/ext4/ext_barebox.c +++ b/fs/ext4/ext_barebox.c @@ -27,15 +27,15 @@ #include <fcntl.h> #include "ext4_common.h" -int ext4fs_devread(struct ext_filesystem *fs, int __sector, int byte_offset, - int byte_len, char *buf) +ssize_t ext4fs_devread(struct ext_filesystem *fs, sector_t __sector, int byte_offset, + size_t byte_len, char *buf) { ssize_t size; uint64_t sector = __sector; size = cdev_read(fs->cdev, buf, byte_len, sector * SECTOR_SIZE + byte_offset, 0); if (size < 0) { - dev_err(fs->dev, "read error at sector %d: %s\n", __sector, + dev_err(fs->dev, "read error at sector %llu: %s\n", __sector, strerror(-size)); return size; } @@ -48,7 +48,7 @@ static inline struct ext2fs_node *to_ext2_node(struct inode *inode) return container_of(inode, struct ext2fs_node, i); } -static int ext_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) +static int ext_read(struct device *_dev, FILE *f, void *buf, size_t insize) { struct inode *inode = f->f_inode; struct ext2fs_node *node = to_ext2_node(inode); @@ -58,7 +58,7 @@ static int ext_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) static struct inode *ext_alloc_inode(struct super_block *sb) { - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct ext_filesystem *fs = fsdev->dev.priv; struct ext2fs_node *node; @@ -118,7 +118,7 @@ static struct dentry *ext_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct ext2fs_node *e2dir = to_ext2_node(dir); - int ret, ino; + int ret, ino = 0; struct inode *inode; ret = ext4fs_get_ino(e2dir, &dentry->d_name, &ino); @@ -127,8 +127,8 @@ static struct dentry *ext_lookup(struct inode *dir, struct dentry *dentry, if (ino) { inode = ext_get_inode(dir->i_sb, ino); - - d_add(dentry, inode); + if (inode) + d_add(dentry, inode); } return NULL; @@ -209,7 +209,7 @@ struct inode *ext_get_inode(struct super_block *sb, int ino) { struct inode *inode; struct ext2fs_node *node; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct ext_filesystem *fs = fsdev->dev.priv; int ret; @@ -218,10 +218,12 @@ struct inode *ext_get_inode(struct super_block *sb, int ino) node = container_of(inode, struct ext2fs_node, i); ret = ext4fs_read_inode(fs->data, ino, &node->inode); + if (ret) + return NULL; inode->i_ino = ino; inode->i_mode = le16_to_cpu(node->inode.mode); - inode->i_size = le32_to_cpu(node->inode.size); + inode->i_size = ext4_isize(node); switch (inode->i_mode & S_IFMT) { default: @@ -247,9 +249,9 @@ struct inode *ext_get_inode(struct super_block *sb, int ino) return inode; } -static int ext_probe(struct device_d *dev) +static int ext_probe(struct device *dev) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); int ret; struct ext_filesystem *fs; struct super_block *sb = &fsdev->sb; @@ -262,29 +264,33 @@ static int ext_probe(struct device_d *dev) ret = fsdev_open_cdev(fsdev); if (ret) - goto err_open; + goto err; fs->cdev = fsdev->cdev; ret = ext4fs_mount(fs); if (ret) - goto err_mount; + goto err; sb->s_op = &ext_ops; inode = ext_get_inode(sb, 2); + if (!inode) { + ret = -EINVAL; + goto err; + } + sb->s_root = d_make_root(inode); return 0; -err_mount: -err_open: +err: free(fs); return ret; } -static void ext_remove(struct device_d *dev) +static void ext_remove(struct device *dev) { struct ext_filesystem *fs = dev->priv; @@ -292,7 +298,7 @@ static void ext_remove(struct device_d *dev) free(fs); } -static struct fs_driver_d ext_driver = { +static struct fs_driver ext_driver = { .read = ext_read, .type = filetype_ext, .flags = 0, diff --git a/fs/ext4/ext_common.h b/fs/ext4/ext_common.h index a28f591bc4..37575d2a1a 100644 --- a/fs/ext4/ext_common.h +++ b/fs/ext4/ext_common.h @@ -232,5 +232,13 @@ struct ext2_data { struct ext4fs_indir_block indir1, indir2, indir3; }; -extern unsigned long part_offset; +static inline loff_t ext4_isize(struct ext2fs_node *node) +{ + if (S_ISREG(le16_to_cpu(node->inode.mode))) + return ((loff_t)le32_to_cpu(node->inode.size_high) << 32) | + le32_to_cpu(node->inode.size); + + return (loff_t) le32_to_cpu(node->inode.size); +} + #endif diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig index bc3b4b69e8..53f784ee54 100644 --- a/fs/fat/Kconfig +++ b/fs/fat/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + menuconfig FS_FAT bool select FS_LEGACY @@ -14,7 +16,7 @@ config FS_FAT_WRITE config FS_FAT_LFN - bool + def_bool y prompt "Support long filenames" help Enable support for file names other than 8.3. diff --git a/fs/fat/Makefile b/fs/fat/Makefile index fe47569bda..7a7a5ccdc6 100644 --- a/fs/fat/Makefile +++ b/fs/fat/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-y += fat.o pbl-y += fat-pbl.o obj-pbl-y += ff.o fat-diskio.o diff --git a/fs/fat/diskio.h b/fs/fat/diskio.h index aee1ce2b0b..57626d2fbd 100644 --- a/fs/fat/diskio.h +++ b/fs/fat/diskio.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + /*----------------------------------------------------------------------- / Low level disk interface modlue include file /-----------------------------------------------------------------------*/ diff --git a/fs/fat/fat-pbl.c b/fs/fat/fat-pbl.c index 93cd6decbc..6b8a807657 100644 --- a/fs/fat/fat-pbl.c +++ b/fs/fat/fat-pbl.c @@ -8,10 +8,10 @@ #define pr_fmt(fmt) "fat-pbl: " fmt #include <common.h> +#include <pbl/bio.h> #include "integer.h" #include "ff.h" #include "diskio.h" -#include "pbl.h" DRESULT disk_read(FATFS *fat, BYTE *buf, DWORD sector, BYTE count) { diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 84bfe69089..f3c7f9b863 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -68,7 +68,7 @@ DRESULT disk_write(FATFS *fat, const BYTE *buf, DWORD sector, BYTE count) /* ---------------------------------------------------------------*/ #ifdef CONFIG_FS_FAT_WRITE -static int fat_create(struct device_d *dev, const char *pathname, mode_t mode) +static int fat_create(struct device *dev, const char *pathname, mode_t mode) { struct fat_priv *priv = dev->priv; FIL f_file; @@ -83,7 +83,7 @@ static int fat_create(struct device_d *dev, const char *pathname, mode_t mode) return 0; } -static int fat_unlink(struct device_d *dev, const char *pathname) +static int fat_unlink(struct device *dev, const char *pathname) { struct fat_priv *priv = dev->priv; int ret; @@ -97,7 +97,7 @@ static int fat_unlink(struct device_d *dev, const char *pathname) return 0; } -static int fat_mkdir(struct device_d *dev, const char *pathname) +static int fat_mkdir(struct device *dev, const char *pathname) { struct fat_priv *priv = dev->priv; int ret; @@ -111,7 +111,7 @@ static int fat_mkdir(struct device_d *dev, const char *pathname) return 0; } -static int fat_rmdir(struct device_d *dev, const char *pathname) +static int fat_rmdir(struct device *dev, const char *pathname) { struct fat_priv *priv = dev->priv; int ret; @@ -125,7 +125,8 @@ static int fat_rmdir(struct device_d *dev, const char *pathname) return 0; } -static int fat_write(struct device_d *_dev, FILE *f, const void *buf, size_t insize) +static int fat_write(struct device *_dev, FILE *f, const void *buf, + size_t insize) { FIL *f_file = f->priv; int outsize; @@ -143,7 +144,7 @@ static int fat_write(struct device_d *_dev, FILE *f, const void *buf, size_t ins return outsize; } -static int fat_truncate(struct device_d *dev, FILE *f, loff_t size) +static int fat_truncate(struct device *dev, FILE *f, loff_t size) { FIL *f_file = f->priv; unsigned long lastofs; @@ -167,7 +168,7 @@ static int fat_truncate(struct device_d *dev, FILE *f, loff_t size) } #endif /* CONFIG_FS_FAT_WRITE */ -static int fat_open(struct device_d *dev, FILE *file, const char *filename) +static int fat_open(struct device *dev, FILE *file, const char *filename) { struct fat_priv *priv = dev->priv; FIL *f_file; @@ -196,6 +197,11 @@ static int fat_open(struct device_d *dev, FILE *file, const char *filename) if (file->flags & O_APPEND) { ret = f_lseek(f_file, f_file->fsize); + if (ret) { + f_close(f_file); + free(f_file); + return -EINVAL; + } } file->priv = f_file; @@ -204,7 +210,7 @@ static int fat_open(struct device_d *dev, FILE *file, const char *filename) return 0; } -static int fat_close(struct device_d *dev, FILE *f) +static int fat_close(struct device *dev, FILE *f) { struct fat_priv *priv = dev->priv; FIL *f_file = f->priv; @@ -218,7 +224,7 @@ static int fat_close(struct device_d *dev, FILE *f) return 0; } -static int fat_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) +static int fat_read(struct device *_dev, FILE *f, void *buf, size_t insize) { int ret; FIL *f_file = f->priv; @@ -234,7 +240,7 @@ static int fat_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) return outsize; } -static int fat_lseek(struct device_d *dev, FILE *f, loff_t pos) +static int fat_lseek(struct device *dev, FILE *f, loff_t pos) { FIL *f_file = f->priv; int ret; @@ -246,7 +252,7 @@ static int fat_lseek(struct device_d *dev, FILE *f, loff_t pos) return 0; } -static DIR* fat_opendir(struct device_d *dev, const char *pathname) +static DIR* fat_opendir(struct device *dev, const char *pathname) { struct fat_priv *priv = dev->priv; DIR *dir; @@ -271,7 +277,7 @@ static DIR* fat_opendir(struct device_d *dev, const char *pathname) return dir; } -static struct dirent* fat_readdir(struct device_d *dev, DIR *dir) +static struct dirent* fat_readdir(struct device *dev, DIR *dir) { FF_DIR *ff_dir = dir->priv; FILINFO finfo; @@ -301,7 +307,7 @@ static struct dirent* fat_readdir(struct device_d *dev, DIR *dir) return &dir->d; } -static int fat_closedir(struct device_d *dev, DIR *dir) +static int fat_closedir(struct device *dev, DIR *dir) { FF_DIR *ff_dir = dir->priv; @@ -311,7 +317,7 @@ static int fat_closedir(struct device_d *dev, DIR *dir) return 0; } -static int fat_stat(struct device_d *dev, const char *filename, struct stat *s) +static int fat_stat(struct device *dev, const char *filename, struct stat *s) { struct fat_priv *priv = dev->priv; FILINFO finfo; @@ -334,9 +340,9 @@ static int fat_stat(struct device_d *dev, const char *filename, struct stat *s) return 0; } -static int fat_probe(struct device_d *dev) +static int fat_probe(struct device *dev) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct fat_priv *priv = xzalloc(sizeof(struct fat_priv)); int ret; @@ -362,12 +368,12 @@ err_open: return ret; } -static void fat_remove(struct device_d *dev) +static void fat_remove(struct device *dev) { free(dev->priv); } -static struct fs_driver_d fat_driver = { +static struct fs_driver fat_driver = { .open = fat_open, .close = fat_close, .read = fat_read, diff --git a/fs/fat/ffconf.h b/fs/fat/ffconf.h index 2f6a6c1544..abf7d1e92e 100644 --- a/fs/fat/ffconf.h +++ b/fs/fat/ffconf.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + /*---------------------------------------------------------------------------/ / FatFs - FAT file system module configuration file R0.08b (C)ChaN, 2011 /----------------------------------------------------------------------------/ diff --git a/fs/fat/integer.h b/fs/fat/integer.h index 04956aa775..fe94e374f3 100644 --- a/fs/fat/integer.h +++ b/fs/fat/integer.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + /*-------------------------------------------*/ /* Integer type definitions for FatFs module */ /*-------------------------------------------*/ @@ -31,6 +31,7 @@ #include <environment.h> #include <libgen.h> #include <block.h> +#include <slice.h> #include <libfile.h> #include <parseopt.h> #include <linux/namei.h> @@ -66,6 +67,150 @@ char *mkmodestr(unsigned long mode, char *str) } EXPORT_SYMBOL(mkmodestr); +void cdev_print(const struct cdev *cdev) +{ + struct device_node *np; + int nbytes; + + if (cdev->dev || cdev->master || cdev->partname) { + printf("Origin: %s", dev_name(cdev->dev) ?: "None"); + if (cdev->master) + printf("\tMaster: %s", cdev->master->name); + if (cdev->partname) + printf("\tPartition: %s", cdev->partname); + printf("\n"); + } + printf("Ocount: %d\tFlags: 0x%02x", cdev->open, cdev->flags); + if (cdev->flags) { + printf(" ("); + if (cdev->flags & DEVFS_IS_CHARACTER_DEV) + printf(" cdev"); + if (cdev->flags & DEVFS_PARTITION_FIXED) + printf(" fixed-partition"); + if (cdev->flags & DEVFS_PARTITION_READONLY) + printf(" readonly-partition"); + if (cdev->flags & DEVFS_PARTITION_FROM_OF) + printf(" of-partition"); + if (cdev->flags & DEVFS_PARTITION_FROM_TABLE) + printf(" table-partition"); + if (cdev->flags & DEVFS_PARTITION_FOR_FIXUP) + printf(" fixup"); + if (cdev->flags & DEVFS_IS_MCI_MAIN_PART_DEV) + printf(" mci-main-partition"); + if (cdev->flags & DEVFS_IS_MBR_PARTITIONED) + printf(" mbr-partitioned"); + if (cdev->flags & DEVFS_IS_GPT_PARTITIONED) + printf(" gpt-partitioned"); + if (cdev->mtd) + printf(" mtd"); + if (cdev->flags & DEVFS_PARTITION_BOOTABLE_ESP) + printf(" boot-esp"); + if (cdev->flags & DEVFS_PARTITION_BOOTABLE_LEGACY) + printf(" boot-legacy"); + printf(" )"); + } + printf("\n"); + + nbytes = 0; + + if (cdev->filetype) + nbytes += printf("Filetype: %s\t", file_type_to_string(cdev->filetype)); + if (cdev_is_mbr_partitioned(cdev->master)) + nbytes += printf("DOS parttype: 0x%02x\t", cdev->dos_partition_type); + else if (cdev_is_gpt_partitioned(cdev->master)) + nbytes += printf("GPT typeuuid: %pUl\t", &cdev->typeuuid); + if (*cdev->partuuid || *cdev->diskuuid) + nbytes += printf("%sUUID: %s", cdev_is_partition(cdev) ? "PART" : "DISK", + cdev_is_partition(cdev) ? cdev->partuuid : cdev->diskuuid); + + if (nbytes) + printf("\n"); + + np = cdev_of_node(cdev); + if (np) + printf("DT node: %pOF\n", np); +} +EXPORT_SYMBOL(cdev_print); + +void stat_print(int dirfd, const char *filename, const struct stat *st) +{ + struct block_device *bdev = NULL; + struct fs_device *fdev; + struct cdev *cdev = NULL; + const char *type = NULL, *typeprefix = ""; + bool is_cdev_link = false; + char modestr[11]; + + mkmodestr(st->st_mode, modestr); + + switch (st->st_mode & S_IFMT) { + case S_IFDIR: type = "directory"; break; + case S_IFBLK: type = "block special file"; break; + case S_IFCHR: type = "character special file"; break; + case S_IFIFO: type = "fifo"; break; + case S_IFLNK: type = "symbolic link"; break; + case S_IFSOCK: type = "socket"; break; + case S_IFREG: type = "regular file"; break; + } + + if (st->st_mode & S_IFCHR) { + char *path; + + path = canonicalize_path(dirfd, filename); + if (path) { + const char *devicefile = devpath_to_name(path); + struct cdev *lcdev; + + lcdev = lcdev_by_name(devicefile); + cdev = cdev_readlink(lcdev); + if (cdev != lcdev) + is_cdev_link = true; + if (cdev) + bdev = cdev_get_block_device(cdev); + + free(path); + } + } + + printf(" File: %s", filename); + + if (S_ISLNK(st->st_mode)) { + char realname[PATH_MAX] = {}; + int ret; + + ret = readlinkat(dirfd, filename, realname, PATH_MAX - 1); + if (ret) + printf(" -> <readlink error %pe>", ERR_PTR(ret)); + else + printf(" -> %s", realname); + } else if (is_cdev_link) { + printf(" ~> %s", cdev->name); + typeprefix = "cdev link to "; + } + + printf("\n"); + + printf(" Size: %-20llu", st->st_size); + if (bdev) + printf("Blocks: %llu\tIO Block: %u\t", + (u64)bdev->num_blocks, 1 << bdev->blockbits); + + if (type) + printf(" %s%s", typeprefix, type); + + fdev = get_fsdevice_by_path(dirfd, filename); + + printf("\nDevice: %s\tInode: %lu\n", + fdev ? dev_name(&fdev->dev) : "<unknown>", + st->st_ino); + printf("Access: (%04o/%s)\tUid: (%u)\tGid: (%u)\n", + st->st_mode & 07777, modestr, st->st_uid, st->st_gid); + + if (cdev) + cdev_print(cdev); +} +EXPORT_SYMBOL(stat_print); + static char *cwd; static struct dentry *cwd_dentry; static struct vfsmount *cwd_mnt; @@ -74,6 +219,8 @@ static FILE *files; static struct dentry *d_root; static struct vfsmount *mnt_root; +static struct fs_driver *ramfs_driver; + static int init_fs(void) { cwd = xzalloc(PATH_MAX); @@ -86,7 +233,12 @@ static int init_fs(void) postcore_initcall(init_fs); -static struct fs_device_d *get_fsdevice_by_path(const char *path); +struct filename; + +static int filename_lookup(int dirfd, struct filename *name, unsigned flags, + struct path *path);; +static struct filename *getname(const char *filename); +static void path_put(const struct path *path); LIST_HEAD(fs_device_list); @@ -110,7 +262,7 @@ static void mntput(struct vfsmount *mnt) static struct vfsmount *lookup_mnt(struct path *path) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; for_each_fs_device(fsdev) { if (path->dentry == fsdev->vfsmount.mountpoint) { @@ -128,18 +280,22 @@ static struct vfsmount *lookup_mnt(struct path *path) */ struct cdev *get_cdev_by_mountpath(const char *path) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; - fsdev = get_fsdevice_by_path(path); + fsdev = get_fsdevice_by_path(AT_FDCWD, path); + if (!fsdev) + return NULL; return fsdev->cdev; } char *get_mounted_path(const char *path) { - struct fs_device_d *fdev; + struct fs_device *fdev; - fdev = get_fsdevice_by_path(path); + fdev = get_fsdevice_by_path(AT_FDCWD, path); + if (!fdev) + return NULL; return fdev->path; } @@ -168,12 +324,16 @@ static void put_file(FILE *f) dput(f->dentry); } -static FILE *fd_to_file(int fd) +static FILE *fd_to_file(int fd, bool o_path_ok) { if (fd < 0 || fd >= MAX_FILES || !files[fd].in_use) { errno = EBADF; return ERR_PTR(-errno); } + if (!o_path_ok && (files[fd].flags & O_PATH)) { + errno = EINVAL; + return ERR_PTR(-errno); + } return &files[fd]; } @@ -193,16 +353,16 @@ static int create(struct dentry *dir, struct dentry *dentry) return inode->i_op->create(inode, dentry, S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO); } -int creat(const char *pathname, mode_t mode) +static int fsdev_truncate(struct device *dev, FILE *f, loff_t length) { - return open(pathname, O_CREAT | O_WRONLY | O_TRUNC); + struct fs_driver *fsdrv = f->fsdev->driver; + + return fsdrv->truncate ? fsdrv->truncate(dev, f, length) : -EROFS; } -EXPORT_SYMBOL(creat); int ftruncate(int fd, loff_t length) { - struct fs_driver_d *fsdrv; - FILE *f = fd_to_file(fd); + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -211,13 +371,9 @@ int ftruncate(int fd, loff_t length) if (f->size == FILE_SIZE_STREAM) return 0; - fsdrv = f->fsdev->driver; - - ret = fsdrv->truncate(&f->fsdev->dev, f, length); - if (ret) { - errno = -ret; - return ret; - } + ret = fsdev_truncate(&f->fsdev->dev, f, length); + if (ret) + return errno_set(ret); f->size = length; f->f_inode->i_size = f->size; @@ -227,8 +383,8 @@ int ftruncate(int fd, loff_t length) int ioctl(int fd, int request, void *buf) { - struct fs_driver_d *fsdrv; - FILE *f = fd_to_file(fd); + struct fs_driver *fsdrv; + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -240,14 +396,13 @@ int ioctl(int fd, int request, void *buf) ret = fsdrv->ioctl(&f->fsdev->dev, f, request, buf); else ret = -ENOSYS; - if (ret) - errno = -ret; - return ret; + + return errno_set(ret); } static ssize_t __read(FILE *f, void *buf, size_t count) { - struct fs_driver_d *fsdrv; + struct fs_driver *fsdrv; int ret; if ((f->flags & O_ACCMODE) == O_WRONLY) { @@ -257,6 +412,9 @@ static ssize_t __read(FILE *f, void *buf, size_t count) fsdrv = f->fsdev->driver; + if (fsdrv != ramfs_driver) + assert_command_context(); + if (f->size != FILE_SIZE_STREAM && f->pos + count > f->size) count = f->size - f->pos; @@ -265,15 +423,13 @@ static ssize_t __read(FILE *f, void *buf, size_t count) ret = fsdrv->read(&f->fsdev->dev, f, buf, count); out: - if (ret < 0) - errno = -ret; - return ret; + return errno_set(ret); } ssize_t pread(int fd, void *buf, size_t count, loff_t offset) { loff_t pos; - FILE *f = fd_to_file(fd); + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -290,7 +446,7 @@ EXPORT_SYMBOL(pread); ssize_t read(int fd, void *buf, size_t count) { - FILE *f = fd_to_file(fd); + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -306,18 +462,24 @@ EXPORT_SYMBOL(read); static ssize_t __write(FILE *f, const void *buf, size_t count) { - struct fs_driver_d *fsdrv; + struct fs_driver *fsdrv; int ret; - if (!(f->flags & O_ACCMODE)) { + fsdrv = f->fsdev->driver; + + if ((f->flags & O_ACCMODE) == O_RDONLY || !fsdrv->write) { ret = -EBADF; goto out; } - fsdrv = f->fsdev->driver; + if (fsdrv != ramfs_driver) + assert_command_context(); + if (f->size != FILE_SIZE_STREAM && f->pos + count > f->size) { - ret = fsdrv->truncate(&f->fsdev->dev, f, f->pos + count); + ret = fsdev_truncate(&f->fsdev->dev, f, f->pos + count); if (ret) { + if (ret == -EPERM) + ret = -ENOSPC; if (ret != -ENOSPC) goto out; count = f->size - f->pos; @@ -330,15 +492,13 @@ static ssize_t __write(FILE *f, const void *buf, size_t count) } ret = fsdrv->write(&f->fsdev->dev, f, buf, count); out: - if (ret < 0) - errno = -ret; - return ret; + return errno_set(ret); } ssize_t pwrite(int fd, const void *buf, size_t count, loff_t offset) { loff_t pos; - FILE *f = fd_to_file(fd); + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -355,7 +515,7 @@ EXPORT_SYMBOL(pwrite); ssize_t write(int fd, const void *buf, size_t count) { - FILE *f = fd_to_file(fd); + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -371,8 +531,8 @@ EXPORT_SYMBOL(write); int flush(int fd) { - struct fs_driver_d *fsdrv; - FILE *f = fd_to_file(fd); + struct fs_driver *fsdrv; + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -384,16 +544,13 @@ int flush(int fd) else ret = 0; - if (ret) - errno = -ret; - - return ret; + return errno_set(ret); } loff_t lseek(int fd, loff_t offset, int whence) { - struct fs_driver_d *fsdrv; - FILE *f = fd_to_file(fd); + struct fs_driver *fsdrv; + FILE *f = fd_to_file(fd, false); loff_t pos; int ret; @@ -402,6 +559,9 @@ loff_t lseek(int fd, loff_t offset, int whence) fsdrv = f->fsdev->driver; + if (fsdrv != ramfs_driver) + assert_command_context(); + ret = -EINVAL; switch (whence) { @@ -434,8 +594,7 @@ loff_t lseek(int fd, loff_t offset, int whence) return pos; out: - if (ret) - errno = -ret; + errno_set(ret); return -1; } @@ -443,8 +602,8 @@ EXPORT_SYMBOL(lseek); int erase(int fd, loff_t count, loff_t offset) { - struct fs_driver_d *fsdrv; - FILE *f = fd_to_file(fd); + struct fs_driver *fsdrv; + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -457,22 +616,23 @@ int erase(int fd, loff_t count, loff_t offset) return -EINVAL; fsdrv = f->fsdev->driver; + + if (fsdrv != ramfs_driver) + assert_command_context(); + if (fsdrv->erase) ret = fsdrv->erase(&f->fsdev->dev, f, count, offset); else ret = -ENOSYS; - if (ret) - errno = -ret; - - return ret; + return errno_set(ret); } EXPORT_SYMBOL(erase); int protect(int fd, size_t count, loff_t offset, int prot) { - struct fs_driver_d *fsdrv; - FILE *f = fd_to_file(fd); + struct fs_driver *fsdrv; + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -483,22 +643,23 @@ int protect(int fd, size_t count, loff_t offset, int prot) count = f->size - offset; fsdrv = f->fsdev->driver; + + if (fsdrv != ramfs_driver) + assert_command_context(); + if (fsdrv->protect) ret = fsdrv->protect(&f->fsdev->dev, f, count, offset, prot); else ret = -ENOSYS; - if (ret) - errno = -ret; - - return ret; + return errno_set(ret); } EXPORT_SYMBOL(protect); int discard_range(int fd, loff_t count, loff_t offset) { - struct fs_driver_d *fsdrv; - FILE *f = fd_to_file(fd); + struct fs_driver *fsdrv; + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -509,15 +670,16 @@ int discard_range(int fd, loff_t count, loff_t offset) count = f->size - offset; fsdrv = f->fsdev->driver; + + if (fsdrv != ramfs_driver) + assert_command_context(); + if (fsdrv->discard_range) ret = fsdrv->discard_range(&f->fsdev->dev, f, count, offset); else ret = -ENOSYS; - if (ret) - errno = -ret; - - return ret; + return errno_set(ret); } int protect_file(const char *file, int prot) @@ -537,8 +699,8 @@ int protect_file(const char *file, int prot) void *memmap(int fd, int flags) { - struct fs_driver_d *fsdrv; - FILE *f = fd_to_file(fd); + struct fs_driver *fsdrv; + FILE *f = fd_to_file(fd, false); void *retp = MAP_FAILED; int ret; @@ -547,51 +709,55 @@ void *memmap(int fd, int flags) fsdrv = f->fsdev->driver; + if (fsdrv != ramfs_driver) + assert_command_context(); + if (fsdrv->memmap) ret = fsdrv->memmap(&f->fsdev->dev, f, &retp, flags); else ret = -EINVAL; - if (ret) - errno = -ret; - + errno_set(ret); return retp; } EXPORT_SYMBOL(memmap); int close(int fd) { - struct fs_driver_d *fsdrv; - FILE *f = fd_to_file(fd); + FILE *f = fd_to_file(fd, true); int ret = 0; if (IS_ERR(f)) return -errno; - fsdrv = f->fsdev->driver; + if (!(f->flags & O_PATH)) { + struct fs_driver *fsdrv; - if (fsdrv->close) - ret = fsdrv->close(&f->fsdev->dev, f); + fsdrv = f->fsdev->driver; - put_file(f); + if (fsdrv != ramfs_driver) + assert_command_context(); - if (ret) - errno = -ret; + if (fsdrv->close) + ret = fsdrv->close(&f->fsdev->dev, f); + } - return ret; + put_file(f); + + return errno_set(ret); } EXPORT_SYMBOL(close); -static int fs_match(struct device_d *dev, struct driver_d *drv) +static int fs_match(struct device *dev, struct driver *drv) { return strcmp(dev->name, drv->name) ? -1 : 0; } -static int fs_probe(struct device_d *dev) +static int fs_probe(struct device *dev) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); - struct driver_d *drv = dev->driver; - struct fs_driver_d *fsdrv = container_of(drv, struct fs_driver_d, drv); + struct fs_device *fsdev = dev_to_fs_device(dev); + struct driver *drv = dev->driver; + struct fs_driver *fsdrv = container_of(drv, struct fs_driver, drv); int ret; ret = dev->driver->probe(dev); @@ -647,11 +813,13 @@ static void destroy_inode(struct inode *inode) free(inode); } -static void fs_remove(struct device_d *dev) +static void fs_remove(struct device *dev) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct super_block *sb = &fsdev->sb; struct inode *inode, *tmp; + struct path path; + int ret; if (fsdev->dev.driver) { dev->driver->remove(dev); @@ -664,22 +832,28 @@ static void fs_remove(struct device_d *dev) if (fsdev->cdev) cdev_close(fsdev->cdev); - if (fsdev->loop && fsdev->cdev) + if (fsdev->loop && fsdev->cdev) { cdev_remove_loop(fsdev->cdev); - dput(sb->s_root); + ret = filename_lookup(AT_FDCWD, getname(fsdev->backingstore), + LOOKUP_FOLLOW, &path); + if (!ret) { + mntput(path.mnt); + path_put(&path); + } + } + + if (fsdev->vfsmount.mountpoint) + fsdev->vfsmount.mountpoint->d_flags &= ~DCACHE_MOUNTED; + dentry_delete_subtree(sb, sb->s_root); list_for_each_entry_safe(inode, tmp, &sb->s_inodes, i_sb_list) destroy_inode(inode); - if (fsdev->vfsmount.mountpoint) - fsdev->vfsmount.mountpoint->d_flags &= ~DCACHE_MOUNTED; - mntput(fsdev->vfsmount.parent); free(fsdev->backingstore); - free(fsdev); } struct bus_type fs_bus = { @@ -695,31 +869,43 @@ static int fs_bus_init(void) } pure_initcall(fs_bus_init); -int register_fs_driver(struct fs_driver_d *fsdrv) +int register_fs_driver(struct fs_driver *fsdrv) { fsdrv->drv.bus = &fs_bus; register_driver(&fsdrv->drv); + if (!strcmp(fsdrv->drv.name, "ramfs")) + ramfs_driver = fsdrv; + return 0; } EXPORT_SYMBOL(register_fs_driver); -static const char *detect_fs(const char *filename, const char *fsoptions) +const char *fs_detect(const char *filename, const char *fsoptions) { enum filetype type; - struct driver_d *drv; - struct fs_driver_d *fdrv; + struct driver *drv; + struct fs_driver *fdrv; bool loop = false; unsigned long long offset = 0; + int ret; parseopt_b(fsoptions, "loop", &loop); parseopt_llu_suffix(fsoptions, "offset", &offset); - if (loop) - type = file_name_detect_type_offset(filename, offset); - else - type = cdev_detect_type(filename); - if (type == filetype_unknown) + if (loop) { + ret = file_name_detect_type_offset(filename, offset, &type); + } else { + struct cdev *cdev = cdev_open_by_name(filename, O_RDONLY); + if (cdev) { + ret = cdev_detect_type(cdev, &type); + cdev_close(cdev); + } else { + ret = -ENOENT; + } + } + + if (ret || type == filetype_unknown) return NULL; bus_for_each_driver(&fs_bus, drv) { @@ -732,22 +918,35 @@ static const char *detect_fs(const char *filename, const char *fsoptions) return NULL; } -int fsdev_open_cdev(struct fs_device_d *fsdev) +int fsdev_open_cdev(struct fs_device *fsdev) { unsigned long long offset = 0; + struct path path = {}; + int ret; parseopt_b(fsdev->options, "loop", &fsdev->loop); parseopt_llu_suffix(fsdev->options, "offset", &offset); - if (fsdev->loop) - fsdev->cdev = cdev_create_loop(fsdev->backingstore, O_RDWR, - offset); - else - fsdev->cdev = cdev_open(fsdev->backingstore, O_RDWR); - if (!fsdev->cdev) + if (fsdev->loop) { + ret = filename_lookup(AT_FDCWD, getname(fsdev->backingstore), + LOOKUP_FOLLOW, &path); + if (ret) + return ret; + + fsdev->cdev = cdev_create_loop(fsdev->backingstore, O_RDWR, offset); + } else { + fsdev->cdev = cdev_open_by_name(fsdev->backingstore, O_RDWR); + } + if (!fsdev->cdev) { + path_put(&path); return -EINVAL; + } + + if (path.mnt) { + mntget(path.mnt); + path_put(&path); + } fsdev->dev.parent = fsdev->cdev->dev; - fsdev->parent_device = fsdev->cdev->dev; return 0; } @@ -757,12 +956,20 @@ static void init_super(struct super_block *sb) INIT_LIST_HEAD(&sb->s_inodes); } -static int fsdev_umount(struct fs_device_d *fsdev) +static int fsdev_umount(struct fs_device *fsdev) { + int ret; + if (fsdev->vfsmount.ref) return -EBUSY; - return unregister_device(&fsdev->dev); + ret = unregister_device(&fsdev->dev); + if (ret) + return ret; + + free(fsdev); + + return 0; } /** @@ -772,8 +979,8 @@ static int fsdev_umount(struct fs_device_d *fsdev) */ int umount_by_cdev(struct cdev *cdev) { - struct fs_device_d *fs; - struct fs_device_d *fs_tmp; + struct fs_device *fs; + struct fs_device *fs_tmp; int first_error = 0; for_each_fs_device_safe(fs_tmp, fs) { @@ -817,6 +1024,21 @@ static int fillonedir(struct dir_context *ctx, const char *name, int namlen, return 0; } +int unreaddir(DIR *dir, const struct dirent *d) +{ + struct readdir_entry *entry; + + if (d != &dir->d) + return -EINVAL; + + entry = xzalloc(sizeof(*entry)); + entry->d = *d; + list_add(&entry->list, &dir->entries); + + return 0; +} +EXPORT_SYMBOL(unreaddir); + struct dirent *readdir(DIR *dir) { struct readdir_entry *entry; @@ -839,7 +1061,6 @@ EXPORT_SYMBOL(readdir); static void stat_inode(struct inode *inode, struct stat *s) { - s->st_dev = 0; s->st_ino = inode->i_ino; s->st_mode = inode->i_mode; s->st_uid = inode->i_uid; @@ -849,7 +1070,7 @@ static void stat_inode(struct inode *inode, struct stat *s) int fstat(int fd, struct stat *s) { - FILE *f = fd_to_file(fd); + FILE *f = fd_to_file(fd, true); if (IS_ERR(f)) return -errno; @@ -868,7 +1089,7 @@ EXPORT_SYMBOL(fstat); */ const char *cdev_get_mount_path(struct cdev *cdev) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; for_each_fs_device(fsdev) { if (fsdev->cdev && fsdev->cdev == cdev) @@ -881,9 +1102,10 @@ const char *cdev_get_mount_path(struct cdev *cdev) /* * cdev_mount_default - mount a cdev to the default path * - * If a cdev is already mounted return the path it's mounted on, otherwise - * mount it to /mnt/<cdevname> and return the path. Returns an error pointer - * on failure. + * If a cdev is already mounted to the default mount path return the path + * it's mounted on. If it is mounted to any other path return EBUSY. + * Otherwise mount it to /mnt/<cdevname> and return the path. Returns an + * error pointer on failure. */ const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions) { @@ -892,15 +1114,24 @@ const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions) int ret; /* - * If this cdev is already mounted somewhere use this path - * instead of mounting it again to avoid corruption on the - * filesystem. Note this ignores eventual fsoptions though. + * If this cdev is already mounted somewhere other than the + * default mount path return -EBUSY instead of mounting it + * again to avoid corruption on the filesystem. Note this + * ignores eventual fsoptions though. If the cdev is already + * mounted on the default path just return that path. */ path = cdev_get_mount_path(cdev); - if (path) - return path; - newpath = basprintf("/mnt/%s", cdev->name); + + if (path) { + if (strcmp(newpath, path)) { + free(newpath); + return ERR_PTR(-EBUSY); + } else { + return path; + } + } + make_directory(newpath); devpath = basprintf("/dev/%s", cdev->name); @@ -918,11 +1149,30 @@ const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions) } /* + * cdev_mount - return existing mount or mount a cdev to the default path + * + * If a cdev is already mounted anywhere return the path + * it's mounted on. + * Otherwise mount it to /mnt/<cdevname> and return the path. Returns an + * error pointer on failure. + */ +const char *cdev_mount(struct cdev *cdev) +{ + const char *path; + + path = cdev_get_mount_path(cdev); + if (path) + return path; + + return cdev_mount_default(cdev, NULL); +} + +/* * mount_all - iterate over block devices and mount all devices we are able to */ void mount_all(void) { - struct device_d *dev; + struct device *dev; struct block_device *bdev; if (!IS_ENABLED(CONFIG_BLOCK)) @@ -932,14 +1182,14 @@ void mount_all(void) device_detect(dev); for_each_block_device(bdev) { - struct cdev *cdev = &bdev->cdev; + struct cdev *cdev; list_for_each_entry(cdev, &bdev->dev->cdevs, devices_list) cdev_mount_default(cdev, NULL); } } -void fsdev_set_linux_rootarg(struct fs_device_d *fsdev, const char *str) +void fsdev_set_linux_rootarg(struct fs_device *fsdev, const char *str) { fsdev->linux_rootarg = xstrdup(str); @@ -956,10 +1206,10 @@ void fsdev_set_linux_rootarg(struct fs_device_d *fsdev, const char *str) */ char *path_get_linux_rootarg(const char *path) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; const char *str; - fsdev = get_fsdevice_by_path(path); + fsdev = get_fsdevice_by_path(AT_FDCWD, path); if (!fsdev) return ERR_PTR(-EINVAL); @@ -980,9 +1230,9 @@ char *path_get_linux_rootarg(const char *path) */ bool __is_tftp_fs(const char *path) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; - fsdev = get_fsdevice_by_path(path); + fsdev = get_fsdevice_by_path(AT_FDCWD, path); if (!fsdev) return false; @@ -1261,7 +1511,6 @@ void d_add(struct dentry *dentry, struct inode *inode) } static bool d_same_name(const struct dentry *dentry, - const struct dentry *parent, const struct qstr *name) { if (dentry->d_name.len != name->len) @@ -1270,17 +1519,16 @@ static bool d_same_name(const struct dentry *dentry, return strncmp(dentry->d_name.name, name->name, name->len) == 0; } -static struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name) +static struct dentry *d_lookup(struct dentry *parent, const struct qstr *name) { struct dentry *dentry; - list_for_each_entry(dentry, &parent->d_subdirs, d_child) { - if (!d_same_name(dentry, parent, name)) - continue; - - dget(dentry); + if (d_same_name(parent, name)) + return dget(parent); - return dentry; + list_for_each_entry(dentry, &parent->d_subdirs, d_child) { + if (d_same_name(dentry, name)) + return dget(dentry); } return NULL; @@ -1370,22 +1618,17 @@ enum {WALK_FOLLOW = 1, WALK_MORE = 2}; struct nameidata { struct path path; struct qstr last; - struct inode *inode; /* path.dentry.d_inode */ unsigned int flags; - unsigned seq, m_seq; int last_type; unsigned depth; int total_link_count; struct saved { struct path link; const char *name; - unsigned seq; } *stack, internal[EMBEDDED_LEVELS]; struct filename *name; - struct nameidata *saved; struct inode *link_inode; - unsigned root_seq; - int dfd; + struct dentry *d_root; }; struct filename { @@ -1393,12 +1636,13 @@ struct filename { int refcnt; }; -static void set_nameidata(struct nameidata *p, int dfd, struct filename *name) +static void set_nameidata(struct nameidata *p, struct filename *name) { + p->last = slash_name; p->stack = p->internal; - p->dfd = dfd; p->name = name; p->total_link_count = 0; + p->d_root = d_root; } static void path_get(const struct path *path) @@ -1423,11 +1667,6 @@ static inline void get_root(struct path *root) static inline void get_pwd(struct path *pwd) { - if (!cwd_dentry) { - cwd_dentry = d_root; - cwd_mnt = mnt_root; - } - pwd->dentry = cwd_dentry; pwd->mnt = cwd_mnt; @@ -1463,9 +1702,7 @@ static int follow_automount(struct path *path, struct nameidata *nd, * as being automount points. These will need the attentions * of the daemon to instantiate them before they can be used. */ - if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | - LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) && - path->dentry->d_inode) + if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && path->dentry->d_inode) return -EISDIR; return automount_mount(path->dentry); @@ -1591,16 +1828,16 @@ static int lookup_fast(struct nameidata *nd, struct path *path) * Return 1 if we went up a level and 0 if we were already at the * root. */ -static int follow_up(struct path *path) +static int follow_up(struct nameidata *nd) { - struct vfsmount *parent, *mnt = path->mnt; + struct path *path = &nd->path; + struct vfsmount *mnt = path->mnt; struct dentry *mountpoint; - parent = mnt->parent; - if (parent == mnt) + if (nd->d_root == path->dentry) return 0; - mntget(parent); + mntget(mnt->parent); mountpoint = dget(mnt->mountpoint); dput(path->dentry); path->dentry = mountpoint; @@ -1642,14 +1879,12 @@ static int follow_dotdot(struct nameidata *nd) break; } - if (!follow_up(&nd->path)) + if (!follow_up(nd)) break; } follow_mount(&nd->path); - nd->inode = nd->path.dentry->d_inode; - return 0; } @@ -1730,7 +1965,6 @@ static inline int step_into(struct nameidata *nd, struct path *path, !(flags & WALK_FOLLOW || nd->flags & LOOKUP_FOLLOW)) { /* not a symlink or should not follow */ path_to_nameidata(path, nd); - nd->inode = inode; return 0; } @@ -1739,7 +1973,7 @@ static inline int step_into(struct nameidata *nd, struct path *path, static int walk_component(struct nameidata *nd, int flags) { - struct path path; + struct path path = {}; int err; /* @@ -1758,16 +1992,9 @@ static int walk_component(struct nameidata *nd, int flags) if (err < 0) return err; - if (err == 0) { - path.mnt = nd->path.mnt; - err = follow_managed(&path, nd); - if (err < 0) - return err; - - if (d_is_negative(path.dentry)) { - path_to_nameidata(&path, nd); - return -ENOENT; - } + if (err == 0 && d_is_negative(path.dentry)) { + path_to_nameidata(&path, nd); + return -ENOENT; } return step_into(nd, &path, flags, d_inode(path.dentry)); @@ -1787,14 +2014,17 @@ static struct filename *getname(const char *filename) { struct filename *result; + if (!*filename) + return ERR_PTR(-ENOENT); + result = malloc(sizeof(*result)); if (!result) - return NULL; + return ERR_PTR(-ENOMEM); result->name = strdup(filename); if (!result->name) { free(result); - return NULL; + return ERR_PTR(-ENOMEM); } result->refcnt = 1; @@ -1813,18 +2043,18 @@ static void putname(struct filename *name) free(name); } -static struct fs_device_d *get_fsdevice_by_dentry(struct dentry *dentry) +static struct fs_device *get_fsdevice_by_dentry(struct dentry *dentry) { struct super_block *sb; sb = dentry->d_sb; - return container_of(sb, struct fs_device_d, sb); + return container_of(sb, struct fs_device, sb); } static bool dentry_is_tftp(struct dentry *dentry) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; fsdev = get_fsdevice_by_dentry(dentry); if (!fsdev) @@ -1849,6 +2079,8 @@ static int link_path_walk(const char *name, struct nameidata *nd) int err; char separator = '/'; + if (!*name) + return -ENOENT; while (*name=='/') name++; if (!*name) @@ -1940,9 +2172,18 @@ OK: } } -static const char *path_init(struct nameidata *nd, unsigned flags) +static bool file_has_flag(FILE *f, unsigned flag) +{ + if (IS_ERR_OR_NULL(f)) + return false; + return (f->flags & flag) == flag; +} + +static const char *path_init(int dirfd, struct nameidata *nd, unsigned flags) { const char *s = nd->name->name; + bool chroot = false; + FILE *f = NULL; nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT; @@ -1951,13 +2192,30 @@ static const char *path_init(struct nameidata *nd, unsigned flags) nd->path.mnt = NULL; nd->path.dentry = NULL; - if (*s == '/') { + /* We don't check for error here yet, as POSIX allows checking + * whether paths are absolute with openat(-1, path, O_PATH) + */ + if (dirfd != AT_FDCWD) { + f = fd_to_file(dirfd, true); + chroot = file_has_flag(f, O_CHROOT); + } + + if (*s == '/' && !chroot) { get_root(&nd->path); - return s; - } else if (nd->dfd == AT_FDCWD) { + } else if (dirfd == AT_FDCWD) { get_pwd(&nd->path); - nd->inode = nd->path.dentry->d_inode; - return s; + } else { + if (IS_ERR(f)) + return ERR_CAST(f); + + nd->path.mnt = &f->fsdev->vfsmount; + nd->path.dentry = f->dentry; + follow_mount(&nd->path); + + if (*s == '/') + nd->path.dentry = nd->path.mnt->mnt_root; + if (chroot) + nd->d_root = nd->path.mnt->mnt_root; } return s; @@ -1995,10 +2253,10 @@ static void terminate_walk(struct nameidata *nd) } /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ -static int path_parentat(struct nameidata *nd, unsigned flags, +static int path_parentat(int dirfd, struct nameidata *nd, unsigned flags, struct path *parent) { - const char *s = path_init(nd, flags); + const char *s = path_init(dirfd, nd, flags); int err; if (IS_ERR(s)) @@ -2014,7 +2272,8 @@ static int path_parentat(struct nameidata *nd, unsigned flags, return err; } -static struct filename *filename_parentat(int dfd, struct filename *name, +static struct filename *filename_parentat(int dirfd, + struct filename *name, unsigned int flags, struct path *parent, struct qstr *last, int *type) { @@ -2024,9 +2283,9 @@ static struct filename *filename_parentat(int dfd, struct filename *name, if (IS_ERR(name)) return name; - set_nameidata(&nd, dfd, name); + set_nameidata(&nd, name); - retval = path_parentat(&nd, flags, parent); + retval = path_parentat(dirfd, &nd, flags, parent); if (likely(!retval)) { *last = nd.last; *type = nd.last_type; @@ -2038,7 +2297,7 @@ static struct filename *filename_parentat(int dfd, struct filename *name, return name; } -static struct dentry *filename_create(int dfd, struct filename *name, +static struct dentry *filename_create(int dirfd, struct filename *name, struct path *path, unsigned int lookup_flags) { struct dentry *dentry = ERR_PTR(-EEXIST); @@ -2047,13 +2306,7 @@ static struct dentry *filename_create(int dfd, struct filename *name, int error; bool is_dir = (lookup_flags & LOOKUP_DIRECTORY); - /* - * Note that only LOOKUP_REVAL and LOOKUP_DIRECTORY matter here. Any - * other flags passed in are ignored! - */ - lookup_flags &= LOOKUP_REVAL; - - name = filename_parentat(dfd, name, 0, path, &last, &type); + name = filename_parentat(dirfd, name, 0, path, &last, &type); if (IS_ERR(name)) return ERR_CAST(name); @@ -2067,7 +2320,6 @@ static struct dentry *filename_create(int dfd, struct filename *name, /* * Do the final lookup. */ - lookup_flags |= LOOKUP_CREATE | LOOKUP_EXCL; dentry = __lookup_hash(&last, path->dentry, lookup_flags); if (IS_ERR(dentry)) goto unlock; @@ -2098,16 +2350,21 @@ out: return dentry; } -static int filename_lookup(int dfd, struct filename *name, unsigned flags, +static int filename_lookup(int dirfd, struct filename *name, unsigned flags, struct path *path) { int err; struct nameidata nd; const char *s; - set_nameidata(&nd, dfd, name); + if (IS_ERR(name)) + return PTR_ERR(name); + + set_nameidata(&nd, name); - s = path_init(&nd, flags); + s = path_init(dirfd, &nd, flags); + if (IS_ERR(s)) + return PTR_ERR(s); while (!(err = link_path_walk(s, &nd)) && ((err = lookup_last(&nd)) > 0)) { s = trailing_symlink(&nd); @@ -2132,13 +2389,13 @@ static int filename_lookup(int dfd, struct filename *name, unsigned flags, return err; } -static struct fs_device_d *get_fsdevice_by_path(const char *pathname) +struct fs_device *get_fsdevice_by_path(int dirfd, const char *pathname) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; struct path path; int ret; - ret = filename_lookup(AT_FDCWD, getname(pathname), 0, &path); + ret = filename_lookup(dirfd, getname(pathname), 0, &path); if (ret) return NULL; @@ -2190,14 +2447,14 @@ static int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) /* libfs.c */ /* ---------------------------------------------------------------- */ -int mkdir (const char *pathname, mode_t mode) +int mkdirat(int dirfd, const char *pathname, mode_t mode) { struct dentry *dentry; struct path path; int error; unsigned int lookup_flags = LOOKUP_DIRECTORY; - dentry = filename_create(AT_FDCWD, getname(pathname), &path, lookup_flags); + dentry = filename_create(dirfd, getname(pathname), &path, lookup_flags); if (IS_ERR(dentry)) { error = PTR_ERR(dentry); goto out; @@ -2208,14 +2465,11 @@ int mkdir (const char *pathname, mode_t mode) dput(dentry); path_put(&path); out: - if (error) - errno = -error; - - return error; + return errno_set(error); } -EXPORT_SYMBOL(mkdir); +EXPORT_SYMBOL(mkdirat); -int rmdir (const char *pathname) +static int rmdirat(int dirfd, const char *pathname) { int error = 0; struct filename *name; @@ -2224,7 +2478,7 @@ int rmdir (const char *pathname) struct qstr last; int type; - name = filename_parentat(AT_FDCWD, getname(pathname), 0, + name = filename_parentat(dirfd, getname(pathname), 0, &path, &last, &type); if (IS_ERR(name)) return PTR_ERR(name); @@ -2263,17 +2517,13 @@ out: path_put(&path); putname(name); - if (error) - errno = -error; - - return error; + return errno_set(error); } -EXPORT_SYMBOL(rmdir); -int open(const char *pathname, int flags, ...) +int openat(int dirfd, const char *pathname, int flags) { - struct fs_device_d *fsdev; - struct fs_driver_d *fsdrv; + struct fs_device *fsdev; + struct fs_driver *fsdrv; struct super_block *sb; FILE *f; int error = 0; @@ -2281,9 +2531,46 @@ int open(const char *pathname, int flags, ...) struct dentry *dentry = NULL; struct nameidata nd; const char *s; + struct filename *filename; - set_nameidata(&nd, AT_FDCWD, getname(pathname)); - s = path_init(&nd, LOOKUP_FOLLOW); + if (flags & O_TMPFILE) { + fsdev = get_fsdevice_by_path(dirfd, pathname); + if (!fsdev) { + errno = ENOENT; + return -errno; + } + + if (fsdev->driver != ramfs_driver) { + errno = EOPNOTSUPP; + return -errno; + } + + f = get_file(); + if (!f) { + errno = EMFILE; + return -errno; + } + + f->path = NULL; + f->dentry = NULL; + f->f_inode = new_inode(&fsdev->sb); + f->f_inode->i_mode = S_IFREG; + f->flags = flags; + f->size = 0; + f->fsdev = fsdev; + + return f->no; + } + + filename = getname(pathname); + if (IS_ERR(filename)) + return PTR_ERR(filename); + + set_nameidata(&nd, filename); + + s = path_init(dirfd, &nd, LOOKUP_FOLLOW); + if (IS_ERR(s)) + return PTR_ERR(s); while (1) { error = link_path_walk(s, &nd); @@ -2333,7 +2620,7 @@ int open(const char *pathname, int flags, ...) error = -ENOENT; goto out1; } - } else { + } else if (!(flags & O_PATH)) { if (d_is_dir(dentry) && !dentry_is_tftp(dentry)) { error = -EISDIR; goto out1; @@ -2348,18 +2635,21 @@ int open(const char *pathname, int flags, ...) goto out1; } - f->path = xstrdup(pathname); + f->path = dpath(dentry, d_root); f->dentry = dentry; f->f_inode = iget(inode); f->flags = flags; f->size = inode->i_size; sb = inode->i_sb; - fsdev = container_of(sb, struct fs_device_d, sb); + fsdev = container_of(sb, struct fs_device, sb); fsdrv = fsdev->driver; f->fsdev = fsdev; + if (flags & O_PATH) + return f->no; + if (fsdrv->open) { char *pathname = dpath(dentry, fsdev->vfsmount.mnt_root); @@ -2370,7 +2660,7 @@ int open(const char *pathname, int flags, ...) } if (flags & O_TRUNC) { - error = fsdrv->truncate(&fsdev->dev, f, 0); + error = fsdev_truncate(&fsdev->dev, f, 0); f->size = 0; inode->i_size = 0; if (error) @@ -2385,21 +2675,37 @@ int open(const char *pathname, int flags, ...) out: put_file(f); out1: + return errno_set(error); +} +EXPORT_SYMBOL(openat); - if (error) - errno = -error; - return error; +static const char *fd_getpath(int fd) +{ + FILE *f; + + if (fd < 0) + return ERR_PTR(errno_set(fd)); + + f = fd_to_file(fd, true); + if (IS_ERR(f)) + return ERR_CAST(f); + + return f->path; } -EXPORT_SYMBOL(open); -int unlink(const char *pathname) +int unlinkat(int dirfd, const char *pathname, int flags) { int ret; struct dentry *dentry; struct inode *inode; struct path path; - ret = filename_lookup(AT_FDCWD, getname(pathname), 0, &path); + if (flags == AT_REMOVEDIR) + return rmdirat(dirfd, pathname); + if (flags) + return -EINVAL; + + ret = filename_lookup(dirfd, getname(pathname), 0, &path); if (ret) goto out; @@ -2426,11 +2732,9 @@ int unlink(const char *pathname) out_put: path_put(&path); out: - if (ret) - errno = -ret; - return ret; + return errno_set(ret); } -EXPORT_SYMBOL(unlink); +EXPORT_SYMBOL(unlinkat); static int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) { @@ -2455,38 +2759,55 @@ int symlink(const char *pathname, const char *newpath) error = vfs_symlink(path.dentry->d_inode, dentry, pathname); out: - if (error) - errno = -error; - - return error; + return errno_set(error); } EXPORT_SYMBOL(symlink); -static void release_dir(DIR *d) +static void __release_dir(DIR *d) { - struct readdir_entry *entry, *tmp; + while (!list_empty(&d->entries)) { + struct readdir_entry *entry = + list_first_entry(&d->entries, struct readdir_entry, list); - list_for_each_entry_safe(entry, tmp, &d->entries, list) { + list_del(&entry->list); free(entry); } - - free(d); } -DIR *opendir(const char *pathname) +static int __opendir(DIR *d) { int ret; - struct dentry *dir; - struct inode *inode; struct file file = {}; - DIR *d; - struct path path = {}; + struct path *path = &d->path; + struct dentry *dir = path->dentry; struct readdir_callback rd = { .ctx = { .actor = fillonedir, }, }; + file.f_path.dentry = dir; + file.f_inode = d_inode(dir); + file.f_op = dir->d_inode->i_fop; + + INIT_LIST_HEAD(&d->entries); + rd.dir = d; + + ret = file.f_op->iterate(&file, &rd.ctx); + if (ret) + __release_dir(d); + + return ret; +} + +DIR *opendir(const char *pathname) +{ + int ret; + struct dentry *dir; + struct inode *inode; + DIR *d; + struct path path = {}; + ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); if (ret) @@ -2506,48 +2827,75 @@ DIR *opendir(const char *pathname) goto out_put; } - file.f_path.dentry = dir; - file.f_inode = d_inode(dir); - file.f_op = dir->d_inode->i_fop; - d = xzalloc(sizeof(*d)); + d->path = path; + d->fd = -ENOENT; - INIT_LIST_HEAD(&d->entries); - rd.dir = d; - - ret = file.f_op->iterate(&file, &rd.ctx); + ret = __opendir(d); if (ret) - goto out_release; - - path_put(&path); + goto out_free; return d; -out_release: - release_dir(d); +out_free: + free(d); out_put: path_put(&path); out: - errno = -ret; + errno_set(ret); return NULL; } EXPORT_SYMBOL(opendir); +DIR *fdopendir(int fd) +{ + const char *path; + DIR *dir; + + path = fd_getpath(fd); + if (IS_ERR(path)) + return NULL; + + dir = opendir(path); + if (!dir) + return NULL; + + /* we intentionally don't increment the reference count, + * as POSIX specifies that fd ownership is transferred + */ + dir->fd = fd; + return dir; +} +EXPORT_SYMBOL(fdopendir); + int closedir(DIR *dir) { - if (!dir) { - errno = EBADF; - return -EBADF; - } + if (!dir) + return errno_set(-EBADF); - release_dir(dir); + path_put(&dir->path); + __release_dir(dir); + if (dir->fd >= 0) + close(dir->fd); + free(dir); return 0; } EXPORT_SYMBOL(closedir); -int readlink(const char *pathname, char *buf, size_t bufsiz) +int rewinddir(DIR *dir) +{ + if (!dir) + return errno_set(-EBADF); + + __release_dir(dir); + + return __opendir(dir); +} +EXPORT_SYMBOL(rewinddir); + +int readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { int ret; struct dentry *dentry; @@ -2555,7 +2903,7 @@ int readlink(const char *pathname, char *buf, size_t bufsiz) const char *link; struct path path = {}; - ret = filename_lookup(AT_FDCWD, getname(pathname), 0, &path); + ret = filename_lookup(dirfd, getname(pathname), 0, &path); if (ret) goto out; @@ -2585,21 +2933,18 @@ int readlink(const char *pathname, char *buf, size_t bufsiz) out_put: path_put(&path); out: - if (ret) - errno = -ret; - - return ret; + return errno_set(ret); } -EXPORT_SYMBOL(readlink); +EXPORT_SYMBOL(readlinkat); -static int stat_filename(const char *filename, struct stat *s, unsigned int flags) +static int stat_filename(int dirfd, const char *filename, struct stat *s, unsigned int flags) { int ret; struct dentry *dentry; struct inode *inode; struct path path = {}; - ret = filename_lookup(AT_FDCWD, getname(filename), flags, &path); + ret = filename_lookup(dirfd, getname(filename), flags, &path); if (ret) goto out; @@ -2618,23 +2963,20 @@ static int stat_filename(const char *filename, struct stat *s, unsigned int flag out_put: path_put(&path); out: - if (ret) - errno = -ret; - - return ret; + return errno_set(ret); } -int stat(const char *filename, struct stat *s) +int statat(int dirfd, const char *filename, struct stat *s) { - return stat_filename(filename, s, LOOKUP_FOLLOW); + return stat_filename(dirfd, filename, s, LOOKUP_FOLLOW); } -EXPORT_SYMBOL(stat); +EXPORT_SYMBOL(statat); -int lstat(const char *filename, struct stat *s) +int lstatat(int dirfd, const char *filename, struct stat *s) { - return stat_filename(filename, s, 0); + return stat_filename(dirfd, filename, s, 0); } -EXPORT_SYMBOL(lstat); +EXPORT_SYMBOL(lstatat); static char *__dpath(struct dentry *dentry, struct dentry *root) { @@ -2646,7 +2988,7 @@ static char *__dpath(struct dentry *dentry, struct dentry *root) return NULL; while (IS_ROOT(dentry)) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; for_each_fs_device(fsdev) { if (dentry == fsdev->vfsmount.mnt_root) { @@ -2690,6 +3032,8 @@ char *dpath(struct dentry *dentry, struct dentry *root) /** * canonicalize_path - resolve links in path + * + * @dirfd: directory file descriptor to look up relative to * @pathname: The input path * * This function resolves all links in @pathname and returns @@ -2697,21 +3041,19 @@ char *dpath(struct dentry *dentry, struct dentry *root) * * Return: Path with links resolved. Allocated, must be freed after use. */ -char *canonicalize_path(const char *pathname) +char *canonicalize_path(int dirfd, const char *pathname) { char *res = NULL; struct path path; int ret; - ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path); + ret = filename_lookup(dirfd, getname(pathname), LOOKUP_FOLLOW, &path); if (ret) goto out; res = dpath(path.dentry, d_root); out: - if (ret) - errno = -ret; - + errno_set(ret); return res; } @@ -2745,12 +3087,93 @@ int chdir(const char *pathname) ret = 0; out: - if (ret) - errno = -ret; + return errno_set(ret); +} +EXPORT_SYMBOL(chdir); + +char *pushd(const char *dir) +{ + char *oldcwd; + int ret; + + oldcwd = strdup(getcwd()); + if (!oldcwd) + return NULL; + + ret = chdir(dir); + if (ret) { + free(oldcwd); + return NULL; + } + + return oldcwd; +} +int popd(char *oldcwd) +{ + int ret; + + if (!oldcwd) + return 0; + + ret = chdir(oldcwd); + free(oldcwd); return ret; } -EXPORT_SYMBOL(chdir); + +static bool cdev_partname_equal(const struct cdev *a, + const struct cdev *b) +{ + return a->partname && b->partname && + !strcmp(a->partname, b->partname); +} + +static char *get_linux_mmcblkdev(const struct cdev *root_cdev) +{ + struct cdev *cdevm = root_cdev->master, *cdev; + int id, partnum; + + if (!IS_ENABLED(CONFIG_MMCBLKDEV_ROOTARG)) + return NULL; + if (!cdevm || !cdev_is_mci_main_part_dev(cdevm)) + return NULL; + + id = of_alias_get_id(cdev_of_node(cdevm), "mmc"); + if (id < 0) + return NULL; + + partnum = 1; /* linux partitions are 1 based */ + list_for_each_entry(cdev, &cdevm->partitions, partition_entry) { + + /* + * Partname is not guaranteed but this partition cdev is listed + * in the partitions list so we need to count it instead of + * skipping it. + */ + if (cdev_partname_equal(root_cdev, cdev)) + return basprintf("root=/dev/mmcblk%dp%d", id, partnum); + partnum++; + } + + return NULL; +} + +char *cdev_get_linux_rootarg(const struct cdev *cdev) +{ + char *str; + + if (!cdev) + return NULL; + + str = get_linux_mmcblkdev(cdev); + if (str) + return str; + + if (cdev->partuuid[0] != 0) + return basprintf("root=PARTUUID=%s", cdev->partuuid); + + return NULL; +} /* * Mount a device to a directory. @@ -2760,7 +3183,7 @@ EXPORT_SYMBOL(chdir); int mount(const char *device, const char *fsname, const char *pathname, const char *fsoptions) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; int ret; struct path path = {}; @@ -2790,14 +3213,14 @@ int mount(const char *device, const char *fsname, const char *pathname, device, pathname, fsname, fsoptions); if (!fsname) - fsname = detect_fs(device, fsoptions); + fsname = fs_detect(device, fsoptions); if (!fsname) { ret = -ENOENT; goto out; } - fsdev = xzalloc(sizeof(struct fs_device_d)); + fsdev = xzalloc(sizeof(struct fs_device)); fsdev->backingstore = xstrdup(device); dev_set_name(&fsdev->dev, fsname); fsdev->dev.id = get_free_deviceid(fsdev->dev.name); @@ -2836,15 +3259,19 @@ int mount(const char *device, const char *fsname, const char *pathname, fsdev->vfsmount.mountpoint = d_root; fsdev->vfsmount.parent = &fsdev->vfsmount; fsdev->path = xstrdup("/"); + + cwd_dentry = d_root; + cwd_mnt = mnt_root; } fsdev->vfsmount.mnt_root = fsdev->sb.s_root; - if (!fsdev->linux_rootarg && fsdev->cdev && fsdev->cdev->partuuid[0] != 0) { - char *str = basprintf("root=PARTUUID=%s", - fsdev->cdev->partuuid); + if (!fsdev->linux_rootarg) { + char *str; - fsdev_set_linux_rootarg(fsdev, str); + str = cdev_get_linux_rootarg(fsdev->cdev); + if (str) + fsdev_set_linux_rootarg(fsdev, str); } path_put(&path); @@ -2858,15 +3285,13 @@ err_register: out: path_put(&path); - errno = -ret; - - return ret; + return errno_set(ret); } EXPORT_SYMBOL(mount); int umount(const char *pathname) { - struct fs_device_d *fsdev = NULL, *f; + struct fs_device *fsdev = NULL, *f; struct path path = {}; int ret; @@ -2889,7 +3314,7 @@ int umount(const char *pathname) path_put(&path); if (!fsdev) { - struct cdev *cdev = cdev_open(pathname, O_RDWR); + struct cdev *cdev = cdev_open_by_name(pathname, O_RDWR); if (cdev) { cdev_close(cdev); @@ -2897,10 +3322,8 @@ int umount(const char *pathname) } } - if (!fsdev) { - errno = EFAULT; - return -EFAULT; - } + if (!fsdev) + return errno_set(-EFAULT); return fsdev_umount(fsdev); } @@ -3026,12 +3449,16 @@ static int automount_mount(struct dentry *dentry) setenv("automount_path", am->path); export("automount_path"); ret = run_command(am->cmd); - setenv("automount_path", NULL); + unsetenv("automount_path"); if (ret) { printf("running automount command '%s' failed\n", am->cmd); ret = -ENODEV; + } else if (!(dentry->d_flags & DCACHE_MOUNTED)) { + printf("automount command '%s' didn't mount anything\n", + am->cmd); + ret = -ENODEV; } break; @@ -3056,7 +3483,6 @@ static int automount_mount(struct dentry *dentry) /* * Some debug commands, helpful to debug the dcache implementation */ -#include <command.h> static int do_lookup_dentry(int argc, char *argv[]) { @@ -3075,7 +3501,7 @@ static int do_lookup_dentry(int argc, char *argv[]) return 1; } - canon = canonicalize_path(argv[1]); + canon = canonicalize_path(AT_FDCWD, argv[1]); printf("path \"%s\":\n", argv[1]); printf("dentry: 0x%p\n", path.dentry); @@ -3096,11 +3522,12 @@ static int do_lookup_dentry(int argc, char *argv[]) BAREBOX_CMD_START(lookup_dentry) .cmd = do_lookup_dentry, + BAREBOX_CMD_GROUP(CMD_GRP_MISC) BAREBOX_CMD_END static struct dentry *debug_follow_mount(struct dentry *dentry) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; unsigned managed = dentry->d_flags; if (managed & DCACHE_MOUNTED) { @@ -3150,5 +3577,6 @@ static int do_debug_fs_dump(int argc, char *argv[]) BAREBOX_CMD_START(debug_fs_dump) .cmd = do_debug_fs_dump, + BAREBOX_CMD_GROUP(CMD_GRP_MISC) BAREBOX_CMD_END #endif diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig index 3121d369b4..329e7b806a 100644 --- a/fs/jffs2/Kconfig +++ b/fs/jffs2/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + menuconfig FS_JFFS2 bool select CRC32 diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index a4da48d3c3..3c5bfd261c 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-y += compr.o dir.o nodelist.o malloc.o obj-y += read.o readinode.o scan.o obj-y += build.o fs.o diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index 12d0271bdd..2e1794f5ae 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2006 NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ struct jffs2_acl_entry { diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index f3fc0ade20..d5757d100b 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +6,6 @@ * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 1c5a7d9137..04b014199f 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -7,9 +8,6 @@ * University of Szeged, Hungary * * Created by Arjan van de Ven <arjan@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <common.h> diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 2e3c368ace..20267beeca 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, * University of Szeged, Hungary * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #ifndef __JFFS2_COMPR_H__ diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c index 1be30dc604..643b83fa74 100644 --- a/fs/jffs2/compr_lzo.c +++ b/fs/jffs2/compr_lzo.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +6,6 @@ * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> * * Created by Richard Purdie <rpurdie@openedhand.com> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #include <common.h> diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index d74d7d3d79..f8bc4ab114 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -6,10 +7,6 @@ * * Created by Arjan van de Ven <arjanv@redhat.com> * - * For licensing information, see the file 'LICENCE' in this directory. - * - * - * * Very simple lz77-ish encoder. * * Theory of operation: Both encoder and decoder have a list of "last diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index 3e4faa739a..91a500f4fb 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +6,6 @@ * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> * * Created by Arjan van de Ven <arjanv@redhat.com> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 222e0d6e5f..2b7914f1f5 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +6,6 @@ * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <common.h> diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c index 536a1786c1..edf8539762 100644 --- a/fs/jffs2/debug.c +++ b/fs/jffs2/debug.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +6,6 @@ * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index 97733ecca7..d40569e6fe 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +7,6 @@ * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #ifndef _JFFS2_DEBUG_H_ diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 4d28d2b553..34f8d141f2 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +6,6 @@ * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <common.h> diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index f094291aa4..6f2cbff6c9 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +6,6 @@ * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <common.h> @@ -42,7 +40,7 @@ static inline void i_gid_write(struct inode *inode, gid_t gid) const struct file_operations jffs2_file_operations; const struct inode_operations jffs2_file_inode_operations; -static int jffs2_open(struct device_d *dev, FILE *file, const char *filename) +static int jffs2_open(struct device *dev, FILE *file, const char *filename) { struct inode *inode = file->f_inode; struct jffs2_file *jf; @@ -58,7 +56,7 @@ static int jffs2_open(struct device_d *dev, FILE *file, const char *filename) return 0; } -static int jffs2_close(struct device_d *dev, FILE *f) +static int jffs2_close(struct device *dev, FILE *f) { struct jffs2_file *jf = f->priv; @@ -74,6 +72,9 @@ static int jffs2_get_block(struct jffs2_file *jf, unsigned int pos) struct jffs2_inode_info *f = JFFS2_INODE_INFO(jf->inode); int ret; + /* pos always has to be 4096 bytes aligned here */ + WARN_ON(pos % JFFS2_BLOCK_SIZE != 0); + if (pos != jf->offset) { ret = jffs2_read_inode_range(c, f, jf->buf, pos, JFFS2_BLOCK_SIZE); @@ -85,7 +86,7 @@ static int jffs2_get_block(struct jffs2_file *jf, unsigned int pos) return 0; } -static int jffs2_read(struct device_d *_dev, FILE *f, void *buf, +static int jffs2_read(struct device *_dev, FILE *f, void *buf, size_t insize) { struct jffs2_file *jf = f->priv; @@ -98,12 +99,13 @@ static int jffs2_read(struct device_d *_dev, FILE *f, void *buf, /* Read till end of current block */ ofs = f->pos % JFFS2_BLOCK_SIZE; if (ofs) { - ret = jffs2_get_block(jf, pos); + ret = jffs2_get_block(jf, f->pos - ofs); /* Align down block */ if (ret) return ret; now = min(size, JFFS2_BLOCK_SIZE - ofs); + /* Complete block has been read, re-apply ofset now */ memcpy(buf, jf->buf + ofs, now); size -= now; pos += now; @@ -397,9 +399,11 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) { } } -static int jffs2_probe(struct device_d *dev) +static int jffs2_probe_cnt; + +static int jffs2_probe(struct device *dev) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; struct super_block *sb; struct jffs2_sb_info *ctx; int ret; @@ -419,28 +423,24 @@ static int jffs2_probe(struct device_d *dev) sb->s_fs_info = ctx; - ret = jffs2_compressors_init(); - if (ret) { - pr_err("error: Failed to initialise compressors\n"); - goto err_out; - } - - ret = jffs2_create_slab_caches(); - if (ret) { - pr_err("error: Failed to initialise slab caches\n"); - goto err_compressors; - } + if (!jffs2_probe_cnt) { + ret = jffs2_compressors_init(); + if (ret) { + pr_err("error: Failed to initialise compressors\n"); + goto err_out; + } + } if (jffs2_fill_super(fsdev, 0)) { dev_err(dev, "no valid jffs2 found\n"); ret = -EINVAL; - goto err_slab; + goto err_compressors; } + jffs2_probe_cnt++; + return 0; -err_slab: - jffs2_destroy_slab_caches(); err_compressors: jffs2_compressors_exit(); err_out: @@ -448,22 +448,25 @@ err_out: return ret; } -static void jffs2_remove(struct device_d *dev) +static void jffs2_remove(struct device *dev) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; struct super_block *sb; fsdev = dev_to_fs_device(dev); sb = &fsdev->sb; - jffs2_destroy_slab_caches(); - jffs2_compressors_exit(); + jffs2_probe_cnt--; + + if (!jffs2_probe_cnt) { + jffs2_compressors_exit(); + } jffs2_put_super(sb); } -static struct fs_driver_d jffs2_driver = { +static struct fs_driver jffs2_driver = { .open = jffs2_open, .close = jffs2_close, .read = jffs2_read, diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index 2d4b03040f..5d420a926d 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +7,6 @@ * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #ifndef _JFFS2_FS_I diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 84d118c2e9..20fa9a26a4 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +7,6 @@ * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #ifndef _JFFS2_FS_SB diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index b7afc68cea..202191be94 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -17,103 +15,10 @@ #include <linux/jffs2.h> #include "nodelist.h" -/* These are initialised to NULL in the kernel startup code. - If you're porting to other operating systems, beware */ -static struct kmem_cache *full_dnode_slab; -static struct kmem_cache *raw_dirent_slab; -static struct kmem_cache *raw_inode_slab; -static struct kmem_cache *tmp_dnode_info_slab; -static struct kmem_cache *raw_node_ref_slab; -static struct kmem_cache *node_frag_slab; -static struct kmem_cache *inode_cache_slab; -#ifdef CONFIG_JFFS2_FS_XATTR -static struct kmem_cache *xattr_datum_cache; -static struct kmem_cache *xattr_ref_cache; -#endif - -int __init jffs2_create_slab_caches(void) -{ - full_dnode_slab = kmem_cache_create("jffs2_full_dnode", - sizeof(struct jffs2_full_dnode), - 0, 0, NULL); - if (!full_dnode_slab) - goto err; - - raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", - sizeof(struct jffs2_raw_dirent), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!raw_dirent_slab) - goto err; - - raw_inode_slab = kmem_cache_create("jffs2_raw_inode", - sizeof(struct jffs2_raw_inode), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!raw_inode_slab) - goto err; - - tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", - sizeof(struct jffs2_tmp_dnode_info), - 0, 0, NULL); - if (!tmp_dnode_info_slab) - goto err; - - raw_node_ref_slab = kmem_cache_create("jffs2_refblock", - sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1), - 0, 0, NULL); - if (!raw_node_ref_slab) - goto err; - - node_frag_slab = kmem_cache_create("jffs2_node_frag", - sizeof(struct jffs2_node_frag), - 0, 0, NULL); - if (!node_frag_slab) - goto err; - - inode_cache_slab = kmem_cache_create("jffs2_inode_cache", - sizeof(struct jffs2_inode_cache), - 0, 0, NULL); - if (!inode_cache_slab) - goto err; - -#ifdef CONFIG_JFFS2_FS_XATTR - xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum", - sizeof(struct jffs2_xattr_datum), - 0, 0, NULL); - if (!xattr_datum_cache) - goto err; - - xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref", - sizeof(struct jffs2_xattr_ref), - 0, 0, NULL); - if (!xattr_ref_cache) - goto err; -#endif - - return 0; - err: - jffs2_destroy_slab_caches(); - return -ENOMEM; -} - -void jffs2_destroy_slab_caches(void) -{ - kmem_cache_destroy(full_dnode_slab); - kmem_cache_destroy(raw_dirent_slab); - kmem_cache_destroy(raw_inode_slab); - kmem_cache_destroy(tmp_dnode_info_slab); - kmem_cache_destroy(raw_node_ref_slab); - kmem_cache_destroy(node_frag_slab); - kmem_cache_destroy(inode_cache_slab); -#ifdef CONFIG_JFFS2_FS_XATTR - kmem_cache_destroy(xattr_datum_cache); - kmem_cache_destroy(xattr_ref_cache); -#endif -} - struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) { struct jffs2_full_dirent *ret; - ret = kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL); + ret = kmalloc(sizeof(*ret) + namesize, GFP_KERNEL); dbg_memalloc("%p\n", ret); return ret; } @@ -127,7 +32,7 @@ void jffs2_free_full_dirent(struct jffs2_full_dirent *x) struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) { struct jffs2_full_dnode *ret; - ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); + ret = malloc(sizeof(*ret)); dbg_memalloc("%p\n", ret); return ret; } @@ -135,13 +40,13 @@ struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) void jffs2_free_full_dnode(struct jffs2_full_dnode *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(full_dnode_slab, x); + free(x); } struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) { struct jffs2_raw_dirent *ret; - ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); + ret = malloc(sizeof(*ret)); dbg_memalloc("%p\n", ret); return ret; } @@ -149,13 +54,13 @@ struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(raw_dirent_slab, x); + free(x); } struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) { struct jffs2_raw_inode *ret; - ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); + ret = malloc(sizeof(*ret)); dbg_memalloc("%p\n", ret); return ret; } @@ -163,13 +68,13 @@ struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) void jffs2_free_raw_inode(struct jffs2_raw_inode *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(raw_inode_slab, x); + free(x); } struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) { struct jffs2_tmp_dnode_info *ret; - ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); + ret = malloc(sizeof(*ret)); dbg_memalloc("%p\n", ret); return ret; @@ -178,14 +83,14 @@ struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(tmp_dnode_info_slab, x); + free(x); } static struct jffs2_raw_node_ref *jffs2_alloc_refblock(void) { struct jffs2_raw_node_ref *ret; - ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); + ret = malloc(sizeof(*ret) * (REFS_PER_BLOCK + 1)); if (ret) { int i = 0; for (i=0; i < REFS_PER_BLOCK; i++) { @@ -242,13 +147,13 @@ int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, void jffs2_free_refblock(struct jffs2_raw_node_ref *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(raw_node_ref_slab, x); + free(x); } struct jffs2_node_frag *jffs2_alloc_node_frag(void) { struct jffs2_node_frag *ret; - ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); + ret = malloc(sizeof(*ret)); dbg_memalloc("%p\n", ret); return ret; } @@ -256,13 +161,13 @@ struct jffs2_node_frag *jffs2_alloc_node_frag(void) void jffs2_free_node_frag(struct jffs2_node_frag *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(node_frag_slab, x); + free(x); } struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) { struct jffs2_inode_cache *ret; - ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); + ret = malloc(sizeof(*ret)); dbg_memalloc("%p\n", ret); return ret; } @@ -270,14 +175,14 @@ struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) void jffs2_free_inode_cache(struct jffs2_inode_cache *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(inode_cache_slab, x); + free(x); } #ifdef CONFIG_JFFS2_FS_XATTR struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) { struct jffs2_xattr_datum *xd; - xd = kmem_cache_zalloc(xattr_datum_cache, GFP_KERNEL); + xd = malloc(sizeof(*ret)); dbg_memalloc("%p\n", xd); if (!xd) return NULL; @@ -291,13 +196,13 @@ struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) void jffs2_free_xattr_datum(struct jffs2_xattr_datum *xd) { dbg_memalloc("%p\n", xd); - kmem_cache_free(xattr_datum_cache, xd); + free(xd); } struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) { struct jffs2_xattr_ref *ref; - ref = kmem_cache_zalloc(xattr_ref_cache, GFP_KERNEL); + ref = malloc(sizeof(*ret)); dbg_memalloc("%p\n", ref); if (!ref) return NULL; @@ -310,6 +215,6 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref) { dbg_memalloc("%p\n", ref); - kmem_cache_free(xattr_ref_cache, ref); + free(ref); } #endif diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 446407e138..94753e1995 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index f78e176e77..b5f7716ce2 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #ifndef __JFFS2_NODELIST_H__ @@ -441,8 +439,6 @@ int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); /* malloc.c */ -int jffs2_create_slab_caches(void); -void jffs2_destroy_slab_caches(void); struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize); void jffs2_free_full_dirent(struct jffs2_full_dirent *); diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index b86a55e482..29915715bb 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -1,12 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #ifndef __JFFS2_OS_LINUX_H__ @@ -18,7 +17,7 @@ struct kstatfs; struct kvec; -struct fs_device_d; +struct fs_device; #define JFFS2_BLOCK_SIZE PAGE_SIZE @@ -181,7 +180,7 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, void jffs2_flash_cleanup(struct jffs2_sb_info *c); /* super.c */ -int jffs2_fill_super(struct fs_device_d *fsdev, int silent); +int jffs2_fill_super(struct fs_device *fsdev, int silent); /* writev.c */ int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index 2848e4d1d8..a1c3b9d47b 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 0fe67cbb6b..aaf2619613 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 64a5e02c21..0d74a8f51f 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index a4b4747825..87a782f11e 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * JFFS2 -- Journalling Flash File System, Version 2. * @@ -5,9 +6,6 @@ * Zoltan Sogor <weth@inf.u-szeged.hu>, * Patrik Kluba <pajko@halom.u-szeged.hu>, * University of Szeged, Hungary - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #ifndef JFFS2_SUMMARY_H diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index d9bb6d0bff..37b3f328c6 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -1,12 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only + /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <common.h> @@ -69,7 +68,7 @@ static const struct super_operations jffs2_super_operations = /* * fill in the superblock */ -int jffs2_fill_super(struct fs_device_d *fsdev, int silent) +int jffs2_fill_super(struct fs_device *fsdev, int silent) { struct super_block *sb = &fsdev->sb; struct jffs2_sb_info *c = sb->s_fs_info; diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index dced873766..e348190bd3 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2006 NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> - * - * For licensing information, see the file 'LICENCE' in this directory. - * */ #ifndef _JFFS2_FS_XATTR_H_ diff --git a/fs/legacy.c b/fs/legacy.c index fc6a18f408..7e886e7ae9 100644 --- a/fs/legacy.c +++ b/fs/legacy.c @@ -19,7 +19,7 @@ static int legacy_iterate(struct file *file, struct dir_context *ctx) struct dentry *dentry = file->f_path.dentry; struct inode *dir = d_inode(dentry); struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct dir *d; struct dirent *dirent; char *pathname; @@ -48,7 +48,7 @@ static struct dentry *legacy_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct inode *inode; char *pathname; struct stat s; @@ -72,7 +72,7 @@ static struct dentry *legacy_lookup(struct inode *dir, struct dentry *dentry, static int legacy_create(struct inode *dir, struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct inode *inode; char *pathname; int ret; @@ -99,7 +99,7 @@ static int legacy_create(struct inode *dir, struct dentry *dentry, umode_t mode) static int legacy_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct inode *inode; char *pathname; int ret; @@ -127,7 +127,7 @@ static int legacy_dir_is_empty(struct dentry *dentry) { struct inode *dir = d_inode(dentry); struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct dir *d; struct dirent *dirent; char *pathname; @@ -147,7 +147,7 @@ static int legacy_dir_is_empty(struct dentry *dentry) static int legacy_rmdir(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); char *pathname; int ret; @@ -176,7 +176,7 @@ static int legacy_rmdir(struct inode *dir, struct dentry *dentry) static int legacy_unlink(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); char *pathname; int ret; @@ -202,7 +202,7 @@ static int legacy_symlink(struct inode *dir, struct dentry *dentry, const char *dest) { struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct inode *inode; char *pathname; int ret; @@ -230,7 +230,7 @@ static int legacy_symlink(struct inode *dir, struct dentry *dentry, static const char *legacy_get_link(struct dentry *dentry, struct inode *inode) { struct super_block *sb = inode->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); char *pathname; int ret; char link[PATH_MAX] = {}; @@ -288,6 +288,7 @@ static struct inode *legacy_get_inode(struct super_block *sb, const struct inode return NULL; case S_IFREG: case S_IFCHR: + case S_IFBLK: inode->i_op = &legacy_file_inode_operations; break; case S_IFDIR: @@ -303,7 +304,7 @@ static struct inode *legacy_get_inode(struct super_block *sb, const struct inode return inode; } -int fs_init_legacy(struct fs_device_d *fsdev) +int fs_init_legacy(struct fs_device *fsdev) { struct inode *inode; @@ -26,7 +26,6 @@ #include <errno.h> #include <libgen.h> #include <fcntl.h> -#include <fs.h> #include <init.h> #include <linux/stat.h> #include <linux/err.h> @@ -119,8 +118,8 @@ struct rpc_reply { uint32_t data[0]; }; -#define NFS_TIMEOUT (2 * SECOND) -#define NFS_MAX_RESEND 5 +#define NFS_TIMEOUT (100 * MSECOND) +#define NFS_MAX_RESEND 100 struct nfs_fh { unsigned short size; @@ -263,6 +262,74 @@ struct nfs_dir { struct nfs_fh fh; }; +struct nfserror { + int ne; + int e; + const char *name; +}; + +static struct nfserror nfserrors[] = { + { .ne = NFS3ERR_PERM, .e = EPERM }, + { .ne = NFS3ERR_NOENT, .e = ENOENT }, + { .ne = NFS3ERR_IO, .e = EIO }, + { .ne = NFS3ERR_NXIO, .e = ENXIO }, + { .ne = NFS3ERR_ACCES, .e = EACCES }, + { .ne = NFS3ERR_EXIST, .e = EEXIST }, + { .ne = NFS3ERR_XDEV, .e = EXDEV }, + { .ne = NFS3ERR_NODEV, .e = ENODEV }, + { .ne = NFS3ERR_NOTDIR, .e = ENOTDIR }, + { .ne = NFS3ERR_ISDIR, .e = EISDIR }, + { .ne = NFS3ERR_INVAL, .e = EINVAL }, + { .ne = NFS3ERR_FBIG, .e = EFBIG }, + { .ne = NFS3ERR_NOSPC, .e = ENOSPC }, + { .ne = NFS3ERR_ROFS, .e = EROFS }, + { .ne = NFS3ERR_MLINK, .e = EMLINK }, + { .ne = NFS3ERR_NAMETOOLONG, .e = ENAMETOOLONG }, + { .ne = NFS3ERR_NOTEMPTY, .e = ENOTEMPTY }, + { .ne = NFS3ERR_DQUOT, .e = EDQUOT }, + { .ne = NFS3ERR_STALE, .e = ESTALE }, + { .ne = NFS3ERR_REMOTE, .e = EREMOTE }, + { .ne = NFS3ERR_NOTSUPP, .e = EOPNOTSUPP }, + { .ne = NFS3ERR_BADHANDLE, .e = EINVAL, .name = "BADHANDLE"}, + { .ne = NFS3ERR_NOT_SYNC, .e = EINVAL, .name = "NOT_SYNC" }, + { .ne = NFS3ERR_BAD_COOKIE, .e = EINVAL, .name = "BAD_COOKIE" }, + { .ne = NFS3ERR_TOOSMALL, .e = EINVAL, .name = "TOOSMALL" }, + { .ne = NFS3ERR_SERVERFAULT, .e = EINVAL, .name = "SERVERFAULT" }, + { .ne = NFS3ERR_BADTYPE, .e = EINVAL, .name = "BADTYPE" }, + { .ne = NFS3ERR_JUKEBOX, .e = EINVAL, .name = "JUKEBOX" }, +}; + +static const char *nfserrstr(u32 nfserror, int *errcode) +{ + static char str[32]; + int i; + + /* + * Most NFS errors have a corresponding POSIX error code. But not all of + * them have one, so some must be mapped to a different code here. + */ + for (i = 0; i < ARRAY_SIZE(nfserrors); i++) { + struct nfserror *err = &nfserrors[i]; + + if (nfserror == err->ne) { + if (errcode) + *errcode = -err->e; + + if (err->name) { + snprintf(str, sizeof(str), "NFS3ERR_%s", err->name); + return str; + } else + return strerror(err->e); + } + } + + if (errcode) + *errcode = -EINVAL; + + snprintf(str, sizeof(str), "Unknown NFS error %d", nfserror); + return str; +} + static void xdr_init(struct xdr_stream *stream, void *buf, int len) { stream->p = stream->buf = buf; @@ -504,6 +571,12 @@ static int rpc_lookup_req(struct nfs_priv *npriv, uint32_t prog, uint32_t ver) nfs_free_packet(nfs_packet); + if (port == 0) { + pr_warn("No UDP port for RPC program %i! " + "Is your NFS server TCP only?\n", prog); + return -ENOENT; + } + return port; } @@ -642,7 +715,7 @@ static uint32_t *nfs_read_post_op_attr(uint32_t *p, struct inode *inode) static int nfs_mount_req(struct nfs_priv *npriv) { uint32_t data[1024]; - uint32_t *p; + uint32_t *p, status; int len; int pathlen; struct packet *nfs_packet; @@ -667,7 +740,18 @@ static int nfs_mount_req(struct nfs_priv *npriv) if (IS_ERR(nfs_packet)) return PTR_ERR(nfs_packet); - p = (void *)nfs_packet->data + sizeof(struct rpc_reply) + 4; + p = (void *)nfs_packet->data + sizeof(struct rpc_reply); + + /* + * Theoretically the error status is one of MNT3ERR_..., but the NFS + * constants are identical. + */ + status = ntoh32(net_read_uint32(p++)); + if (status != NFS3_OK) { + int ret; + pr_err("Mounting failed: %s\n", nfserrstr(status, &ret)); + return ret; + } npriv->rootfh.size = ntoh32(net_read_uint32(p++)); if (npriv->rootfh.size > NFS3_FHSIZE) { @@ -719,7 +803,7 @@ static int nfs_lookup_req(struct nfs_priv *npriv, struct nfs_fh *fh, { struct nfs_inode *ninode = nfsi(inode); uint32_t data[1024]; - uint32_t *p; + uint32_t *p, status; int len; struct packet *nfs_packet; @@ -761,7 +845,13 @@ static int nfs_lookup_req(struct nfs_priv *npriv, struct nfs_fh *fh, if (IS_ERR(nfs_packet)) return PTR_ERR(nfs_packet); - p = (void *)nfs_packet->data + sizeof(struct rpc_reply) + 4; + p = (void *)nfs_packet->data + sizeof(struct rpc_reply); + status = ntoh32(net_read_uint32(p++)); + if (status != NFS3_OK) { + int ret; + pr_err("Lookup failed: %s\n", nfserrstr(status, &ret)); + return ret; + } ninode->fh.size = ntoh32(net_read_uint32(p++)); if (ninode->fh.size > NFS3_FHSIZE) { @@ -787,7 +877,7 @@ static int nfs_lookup_req(struct nfs_priv *npriv, struct nfs_fh *fh, static void *nfs_readdirattr_req(struct nfs_priv *npriv, struct nfs_dir *dir) { uint32_t data[1024]; - uint32_t *p; + uint32_t *p, status; int len; struct packet *nfs_packet; void *buf; @@ -845,7 +935,13 @@ static void *nfs_readdirattr_req(struct nfs_priv *npriv, struct nfs_dir *dir) if (IS_ERR(nfs_packet)) return NULL; - p = (void *)nfs_packet->data + sizeof(struct rpc_reply) + 4; + p = (void *)nfs_packet->data + sizeof(struct rpc_reply); + status = ntoh32(net_read_uint32(p++)); + if (status != NFS3_OK) { + pr_err("Readdir failed: %s\n", nfserrstr(status, NULL)); + return NULL; + } + p = nfs_read_post_op_attr(p, NULL); /* update cookieverf */ @@ -879,8 +975,8 @@ static int nfs_read_req(struct file_priv *priv, uint64_t offset, uint32_t readlen) { uint32_t data[1024]; - uint32_t *p; - int len; + uint32_t *p, status; + int len, ret; struct packet *nfs_packet; uint32_t rlen, eof; @@ -922,7 +1018,12 @@ static int nfs_read_req(struct file_priv *priv, uint64_t offset, if (IS_ERR(nfs_packet)) return PTR_ERR(nfs_packet); - p = (void *)nfs_packet->data + sizeof(struct rpc_reply) + 4; + p = (void *)nfs_packet->data + sizeof(struct rpc_reply); + status = ntoh32(net_read_uint32(p++)); + if (status != NFS3_OK) { + pr_err("Read failed: %s\n", nfserrstr(status, &ret)); + return ret; + } p = nfs_read_post_op_attr(p, NULL); @@ -964,7 +1065,7 @@ static void nfs_handler(void *ctx, char *p, unsigned len) list_add_tail(&packet->list, &npriv->packets); } -static int nfs_truncate(struct device_d *dev, FILE *f, loff_t size) +static int nfs_truncate(struct device *dev, FILE *f, loff_t size) { return -ENOSYS; } @@ -981,7 +1082,7 @@ static int nfs_readlink_req(struct nfs_priv *npriv, struct nfs_fh *fh, char **target) { uint32_t data[1024]; - uint32_t *p; + uint32_t *p, status; uint32_t len; struct packet *nfs_packet; @@ -1017,13 +1118,19 @@ static int nfs_readlink_req(struct nfs_priv *npriv, struct nfs_fh *fh, if (IS_ERR(nfs_packet)) return PTR_ERR(nfs_packet); - p = (void *)nfs_packet->data + sizeof(struct rpc_reply) + 4; + p = (void *)nfs_packet->data + sizeof(struct rpc_reply); + status = ntoh32(net_read_uint32(p++)); + if (status != NFS3_OK) { + int ret; + pr_err("Readlink failed: %s\n", nfserrstr(status, &ret)); + return ret; + } p = nfs_read_post_op_attr(p, NULL); len = ntoh32(net_read_uint32(p)); /* new path length */ - len = max_t(unsigned int, len, + len = min_t(unsigned int, len, nfs_packet->len - sizeof(struct rpc_reply) - sizeof(uint32_t)); p++; @@ -1049,7 +1156,7 @@ static const char *nfs_get_link(struct dentry *dentry, struct inode *inode) return inode->i_link; } -static int nfs_open(struct device_d *dev, FILE *file, const char *filename) +static int nfs_open(struct device *dev, FILE *file, const char *filename) { struct inode *inode = file->f_inode; struct nfs_inode *ninode = nfsi(inode); @@ -1071,7 +1178,7 @@ static int nfs_open(struct device_d *dev, FILE *file, const char *filename) return 0; } -static int nfs_close(struct device_d *dev, FILE *file) +static int nfs_close(struct device *dev, FILE *file) { struct file_priv *priv = file->priv; @@ -1080,13 +1187,13 @@ static int nfs_close(struct device_d *dev, FILE *file) return 0; } -static int nfs_write(struct device_d *_dev, FILE *file, const void *inbuf, - size_t insize) +static int nfs_write(struct device *_dev, FILE *file, const void *inbuf, + size_t insize) { return -ENOSYS; } -static int nfs_read(struct device_d *dev, FILE *file, void *buf, size_t insize) +static int nfs_read(struct device *dev, FILE *file, void *buf, size_t insize) { struct file_priv *priv = file->priv; @@ -1102,7 +1209,7 @@ static int nfs_read(struct device_d *dev, FILE *file, void *buf, size_t insize) return kfifo_get(priv->fifo, buf, insize); } -static int nfs_lseek(struct device_d *dev, FILE *file, loff_t pos) +static int nfs_lseek(struct device *dev, FILE *file, loff_t pos) { struct file_priv *priv = file->priv; @@ -1285,7 +1392,7 @@ static const struct super_operations nfs_ops = { static char *rootnfsopts; -static void nfs_set_rootarg(struct nfs_priv *npriv, struct fs_device_d *fsdev) +static void nfs_set_rootarg(struct nfs_priv *npriv, struct fs_device *fsdev) { char *str, *tmp; const char *bootargs; @@ -1318,9 +1425,9 @@ static void nfs_set_rootarg(struct nfs_priv *npriv, struct fs_device_d *fsdev) free(str); } -static int nfs_probe(struct device_d *dev) +static int nfs_probe(struct device *dev) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct nfs_priv *npriv = xzalloc(sizeof(struct nfs_priv)); struct super_block *sb = &fsdev->sb; char *tmp = xstrdup(fsdev->backingstore); @@ -1418,7 +1525,7 @@ err: return ret; } -static void nfs_remove(struct device_d *dev) +static void nfs_remove(struct device *dev) { struct nfs_priv *npriv = dev->priv; @@ -1429,7 +1536,7 @@ static void nfs_remove(struct device_d *dev) free(npriv); } -static struct fs_driver_d nfs_driver = { +static struct fs_driver nfs_driver = { .open = nfs_open, .close = nfs_close, .read = nfs_read, diff --git a/fs/omap4_usbbootfs.c b/fs/omap4_usbbootfs.c index 4f159210d1..30392d1192 100644 --- a/fs/omap4_usbbootfs.c +++ b/fs/omap4_usbbootfs.c @@ -17,7 +17,7 @@ #include <init.h> #include <linux/stat.h> #include <linux/err.h> -#include <mach/omap4_rom_usb.h> +#include <mach/omap/omap4_rom_usb.h> #define OMAP4_USBBOOT_FS_MAGIC 0x5562464D #define OMAP4_USBBOOT_FS_CMD_OPEN 0x46530000 @@ -30,8 +30,9 @@ struct file_priv { u32 size; }; -static struct file_priv *omap4_usbbootfs_do_open( - struct device_d *dev, int accmode, const char *filename) +static struct file_priv *omap4_usbbootfs_do_open(struct device *dev, + int accmode, + const char *filename) { struct file_priv *priv; u32 data; @@ -60,8 +61,8 @@ static struct file_priv *omap4_usbbootfs_do_open( return priv; } -static int omap4_usbbootfs_open( - struct device_d *dev, FILE *file, const char *filename) +static int omap4_usbbootfs_open(struct device *dev, FILE *file, + const char *filename) { struct file_priv *priv; @@ -86,14 +87,14 @@ static int omap4_usbbootfs_do_close(struct file_priv *priv) return 0; } -static int omap4_usbbootfs_close(struct device_d *dev, FILE *f) +static int omap4_usbbootfs_close(struct device *dev, FILE *f) { struct file_priv *priv = f->priv; return omap4_usbbootfs_do_close(priv); } -static int omap4_usbbootfs_read( - struct device_d *dev, FILE *f, void *buf, size_t size) +static int omap4_usbbootfs_read(struct device *dev, FILE *f, void *buf, + size_t size) { struct file_priv *priv = f->priv; u32 data; @@ -116,13 +117,13 @@ static int omap4_usbbootfs_read( return size; } -static DIR *omap4_usbbootfs_opendir(struct device_d *dev, const char *pathname) +static DIR *omap4_usbbootfs_opendir(struct device *dev, const char *pathname) { return NULL; } -static int omap4_usbbootfs_stat( - struct device_d *dev, const char *filename, struct stat *s) +static int omap4_usbbootfs_stat(struct device *dev, const char *filename, + struct stat *s) { struct file_priv *priv; @@ -140,15 +141,16 @@ static int omap4_usbbootfs_stat( return 0; } -static int omap4_usbbootfs_probe(struct device_d *dev) +static int omap4_usbbootfs_probe(struct device *dev) { - return 0; + return omap4_usbboot_open(); } -static void omap4_usbbootfs_remove(struct device_d *dev) + +static void omap4_usbbootfs_remove(struct device *dev) { } -static struct fs_driver_d omap4_usbbootfs_driver = { +static struct fs_driver omap4_usbbootfs_driver = { .open = omap4_usbbootfs_open, .close = omap4_usbbootfs_close, .read = omap4_usbbootfs_read, diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index 30c2de19c8..ff9091d3f3 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + menuconfig FS_PSTORE select FS_LEGACY bool diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile index c4043e1a8f..18475497a3 100644 --- a/fs/pstore/Makefile +++ b/fs/pstore/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + # # Makefile for the linux pstorefs routines. # diff --git a/fs/pstore/fs.c b/fs/pstore/fs.c index e9c7ae7adb..777e2448cc 100644 --- a/fs/pstore/fs.c +++ b/fs/pstore/fs.c @@ -21,7 +21,6 @@ #include <fs.h> #include <errno.h> #include <fcntl.h> -#include <fs.h> #include <malloc.h> #include <init.h> #include <linux/stat.h> @@ -30,7 +29,6 @@ #include <libbb.h> #include <rtc.h> #include <libfile.h> -#include <linux/pstore.h> #include "internal.h" struct list_head allpstore = LIST_HEAD_INIT(allpstore); @@ -140,7 +138,7 @@ static struct pstore_private *pstore_get_by_name(struct list_head *head, return NULL; } -static int pstore_open(struct device_d *dev, FILE *file, const char *filename) +static int pstore_open(struct device *dev, FILE *file, const char *filename) { struct list_head *head = dev->priv; struct pstore_private *d; @@ -159,12 +157,12 @@ static int pstore_open(struct device_d *dev, FILE *file, const char *filename) return 0; } -static int pstore_close(struct device_d *dev, FILE *file) +static int pstore_close(struct device *dev, FILE *file) { return 0; } -static int pstore_read(struct device_d *dev, FILE *file, void *buf, +static int pstore_read(struct device *dev, FILE *file, void *buf, size_t insize) { struct pstore_private *d = file->priv; @@ -175,7 +173,7 @@ static int pstore_read(struct device_d *dev, FILE *file, void *buf, return insize; } -static int pstore_lseek(struct device_d *dev, FILE *file, loff_t pos) +static int pstore_lseek(struct device *dev, FILE *file, loff_t pos) { struct pstore_private *d = file->priv; @@ -184,7 +182,7 @@ static int pstore_lseek(struct device_d *dev, FILE *file, loff_t pos) return 0; } -static DIR *pstore_opendir(struct device_d *dev, const char *pathname) +static DIR *pstore_opendir(struct device *dev, const char *pathname) { DIR *dir; @@ -198,7 +196,7 @@ static DIR *pstore_opendir(struct device_d *dev, const char *pathname) return dir; } -static struct dirent *pstore_readdir(struct device_d *dev, DIR *dir) +static struct dirent *pstore_readdir(struct device *dev, DIR *dir) { struct pstore_private *d = dir->priv; @@ -211,14 +209,14 @@ static struct dirent *pstore_readdir(struct device_d *dev, DIR *dir) return &dir->d; } -static int pstore_closedir(struct device_d *dev, DIR *dir) +static int pstore_closedir(struct device *dev, DIR *dir) { free(dir); return 0; } -static int pstore_stat(struct device_d *dev, const char *filename, +static int pstore_stat(struct device *dev, const char *filename, struct stat *s) { struct pstore_private *d; @@ -236,7 +234,7 @@ static int pstore_stat(struct device_d *dev, const char *filename, return 0; } -static void pstore_remove(struct device_d *dev) +static void pstore_remove(struct device *dev) { struct pstore_private *d, *tmp; @@ -245,7 +243,7 @@ static void pstore_remove(struct device_d *dev) } } -static int pstore_probe(struct device_d *dev) +static int pstore_probe(struct device *dev) { struct list_head *priv = &allpstore; @@ -256,7 +254,7 @@ static int pstore_probe(struct device_d *dev) return 0; } -static struct fs_driver_d pstore_driver = { +static struct fs_driver pstore_driver = { .open = pstore_open, .close = pstore_close, .read = pstore_read, diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h index 6b507e4bd3..d233ee7e8c 100644 --- a/fs/pstore/internal.h +++ b/fs/pstore/internal.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + #ifndef __PSTORE_INTERNAL_H__ #define __PSTORE_INTERNAL_H__ diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index f4b77226d9..50a1bffdd0 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -27,7 +27,7 @@ #include <linux/mutex.h> #include <console.h> #include <malloc.h> -#include <printk.h> +#include <linux/printk.h> #include <module.h> #include "internal.h" diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 958f46b0ea..4732bd4e31 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -31,7 +31,7 @@ #include <linux/log2.h> #include <linux/spinlock.h> #include <malloc.h> -#include <printk.h> +#include <linux/printk.h> #include <stdio.h> #include <globalvar.h> #include <init.h> @@ -410,13 +410,13 @@ static int ramoops_init_prz(const char *name, return 0; } -static int ramoops_parse_dt_size(struct device_d *dev, +static int ramoops_parse_dt_size(struct device *dev, const char *propname, u32 *value) { u32 val32 = 0; int ret; - ret = of_property_read_u32(dev->device_node, propname, &val32); + ret = of_property_read_u32(dev->of_node, propname, &val32); if (ret < 0 && ret != -EINVAL) { dev_err(dev, "failed to parse property %s: %d\n", propname, ret); @@ -432,10 +432,10 @@ static int ramoops_parse_dt_size(struct device_d *dev, return 0; } -static int ramoops_parse_dt(struct device_d *dev, +static int ramoops_parse_dt(struct device *dev, struct ramoops_platform_data *pdata) { - struct device_node *of_node = dev->device_node; + struct device_node *of_node = dev->of_node; struct resource *res; u32 value; int ret; @@ -474,37 +474,24 @@ static int ramoops_of_fixup(struct device_node *root, void *data) { struct ramoops_platform_data *pdata = data; struct device_node *node; - u32 reg[2]; + struct resource res = {}; int ret; - node = of_get_child_by_name(root, "reserved-memory"); - if (!node) { - pr_info("Adding reserved-memory node\n"); - node = of_create_node(root, "/reserved-memory"); - if (!node) - return -ENOMEM; + res.start = pdata->mem_address; + res.end = res.start + pdata->mem_size; + res.name = "ramoops"; - of_property_write_u32(node, "#address-cells", 1); - of_property_write_u32(node, "#size-cells", 1); - of_new_property(node, "ranges", NULL, 0); - } + ret = of_fixup_reserved_memory(root, &res); + if (ret) + return ret; - node = of_get_child_by_name(node, "ramoops"); - if (!node) { - pr_info("Adding ramoops node\n"); - node = of_create_node(root, "/reserved-memory/ramoops"); - if (!node) - return -ENOMEM; - } + node = of_find_node_by_path_from(root, "/reserved-memory/ramoops"); + if (!node) + return -ENOMEM; ret = of_property_write_string(node, "compatible", "ramoops"); if (ret) return ret; - reg[0] = pdata->mem_address; - reg[1] = pdata->mem_size; - ret = of_property_write_u32_array(node, "reg", reg, 2); - if (ret) - return ret; ret = of_property_write_bool(node, "unbuffered", pdata->mem_type); if (ret) @@ -530,7 +517,7 @@ static int ramoops_of_fixup(struct device_node *root, void *data) return 0; } -static int ramoops_probe(struct device_d *dev) +static int ramoops_probe(struct device *dev) { struct ramoops_platform_data *pdata = dummy_data; struct ramoops_context *cxt = &oops_cxt; @@ -639,7 +626,6 @@ static int ramoops_probe(struct device_d *dev) ramoops_ecc); globalvar_add_simple("linux.bootargs.ramoops", kernelargs); } else { - of_add_reserve_entry(cxt->phys_addr, cxt->phys_addr + mem_size); of_register_fixup(ramoops_of_fixup, pdata); } @@ -689,8 +675,9 @@ static const struct of_device_id ramoops_dt_ids[] = { { .compatible = "ramoops" }, { }, }; +MODULE_DEVICE_TABLE(of, ramoops_dt_ids); -static struct driver_d ramoops_driver = { +static struct driver ramoops_driver = { .name = "ramoops", .probe = ramoops_probe, .of_compatible = DRV_OF_COMPAT(ramoops_dt_ids), diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index 06be47ce53..76b8a109be 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -20,7 +20,6 @@ #include <linux/rslib.h> #include <linux/pstore_ram.h> #include <linux/string.h> -#include <linux/rslib.h> #include <stdio.h> #include <malloc.h> #include <memory.h> diff --git a/fs/ramfs.c b/fs/ramfs.c index 14ba877660..117e69b70c 100644 --- a/fs/ramfs.c +++ b/fs/ramfs.c @@ -221,7 +221,7 @@ static struct ramfs_chunk *ramfs_find_chunk(struct ramfs_inode *node, return NULL; } -static int ramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) +static int ramfs_read(struct device *_dev, FILE *f, void *buf, size_t insize) { struct inode *inode = f->f_inode; struct ramfs_inode *node = to_ramfs_inode(inode); @@ -251,7 +251,8 @@ static int ramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) return insize; } -static int ramfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t insize) +static int ramfs_write(struct device *_dev, FILE *f, const void *buf, + size_t insize) { struct inode *inode = f->f_inode; struct ramfs_inode *node = to_ramfs_inode(inode); @@ -355,7 +356,7 @@ out: return -ENOSPC; } -static int ramfs_truncate(struct device_d *dev, FILE *f, loff_t size) +static int ramfs_truncate(struct device *dev, FILE *f, loff_t size) { struct inode *inode = f->f_inode; struct ramfs_inode *node = to_ramfs_inode(inode); @@ -387,7 +388,7 @@ static int ramfs_truncate(struct device_d *dev, FILE *f, loff_t size) return 0; } -static int ramfs_memmap(struct device_d *_dev, FILE *f, void **map, int flags) +static int ramfs_memmap(struct device *_dev, FILE *f, void **map, int flags) { struct inode *inode = f->f_inode; struct ramfs_inode *node = to_ramfs_inode(inode); @@ -431,10 +432,10 @@ static const struct super_operations ramfs_ops = { .destroy_inode = ramfs_destroy_inode, }; -static int ramfs_probe(struct device_d *dev) +static int ramfs_probe(struct device *dev) { struct inode *inode; - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct super_block *sb = &fsdev->sb; sb->s_op = &ramfs_ops; @@ -445,12 +446,11 @@ static int ramfs_probe(struct device_d *dev) return 0; } -static void ramfs_remove(struct device_d *dev) +static void ramfs_remove(struct device *dev) { - free(dev->priv); } -static struct fs_driver_d ramfs_driver = { +static struct fs_driver ramfs_driver = { .read = ramfs_read, .write = ramfs_write, .memmap = ramfs_memmap, diff --git a/fs/ratpfs.c b/fs/ratpfs.c index b6857c6016..9e85fc596e 100644 --- a/fs/ratpfs.c +++ b/fs/ratpfs.c @@ -48,25 +48,25 @@ struct ratpfs_dir { DIR dir; }; -static int ratpfs_create(struct device_d __always_unused *dev, - const char __always_unused *pathname, - mode_t __always_unused mode) +static int ratpfs_create(struct device __always_unused *dev, + const char __always_unused *pathname, + mode_t __always_unused mode) { pr_debug("%s\n", __func__); return 0; } -static int ratpfs_mkdir(struct device_d __always_unused *dev, - const char __always_unused *pathname) +static int ratpfs_mkdir(struct device __always_unused *dev, + const char __always_unused *pathname) { pr_debug("%s\n", __func__); return -ENOSYS; } -static int ratpfs_rm(struct device_d __always_unused *dev, - const char *pathname) +static int ratpfs_rm(struct device __always_unused *dev, + const char *pathname) { pr_debug("%s\n", __func__); @@ -76,8 +76,8 @@ static int ratpfs_rm(struct device_d __always_unused *dev, return 0; } -static int ratpfs_truncate(struct device_d __always_unused *dev, - FILE *f, loff_t size) +static int ratpfs_truncate(struct device __always_unused *dev, + FILE *f, loff_t size) { int len_tx = 1 /* type */ + 4 /* handle */ @@ -114,8 +114,8 @@ out: return ret; } -static int ratpfs_open(struct device_d __always_unused *dev, - FILE *file, const char *filename) +static int ratpfs_open(struct device __always_unused *dev, + FILE *file, const char *filename) { int len_name = strlen(filename); int len_tx = 1 /* type */ @@ -163,7 +163,7 @@ out: return ret; } -static int ratpfs_close(struct device_d __always_unused *dev, +static int ratpfs_close(struct device __always_unused *dev, FILE *f) { int len_tx = 1 /* type */ @@ -198,7 +198,7 @@ out: return ret; } -static int ratpfs_write(struct device_d __always_unused *dev, +static int ratpfs_write(struct device __always_unused *dev, FILE *f, const void *buf, size_t orig_size) { int size = min((int)orig_size, 4096); @@ -241,7 +241,7 @@ out: return ret; } -static int ratpfs_read(struct device_d __always_unused *dev, +static int ratpfs_read(struct device __always_unused *dev, FILE *f, void *buf, size_t orig_size) { int size = min((int)orig_size, 4096); @@ -284,8 +284,8 @@ out: return ret; } -static DIR* ratpfs_opendir(struct device_d __always_unused *dev, - const char *pathname) +static DIR* ratpfs_opendir(struct device __always_unused *dev, + const char *pathname) { int len_name = strlen(pathname); int len_tx = 1 /* type */ @@ -318,7 +318,7 @@ static DIR* ratpfs_opendir(struct device_d __always_unused *dev, } } -static struct dirent *ratpfs_readdir(struct device_d *dev, DIR *dir) +static struct dirent *ratpfs_readdir(struct device *dev, DIR *dir) { struct ratpfs_dir *rdir = container_of(dir, struct ratpfs_dir, dir); int i; @@ -338,7 +338,7 @@ static struct dirent *ratpfs_readdir(struct device_d *dev, DIR *dir) return &dir->d; } -static int ratpfs_closedir(struct device_d *dev, DIR *dir) +static int ratpfs_closedir(struct device *dev, DIR *dir) { struct ratpfs_dir *rdir = container_of(dir, struct ratpfs_dir, dir); @@ -350,8 +350,8 @@ static int ratpfs_closedir(struct device_d *dev, DIR *dir) return 0; } -static int ratpfs_stat(struct device_d __always_unused *dev, - const char *filename, struct stat *s) +static int ratpfs_stat(struct device __always_unused *dev, + const char *filename, struct stat *s) { int len_name = strlen(filename); int len_tx = 1 /* type */ @@ -395,13 +395,13 @@ out: return ret; } -static int ratpfs_probe(struct device_d *dev) +static int ratpfs_probe(struct device *dev) { int len_tx = 1; /* type */ struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx); struct ratp_bb_pkt *pkt_rx = NULL; int ret; - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); pr_debug("%s\n", __func__); @@ -431,14 +431,14 @@ out: return ret; } -static void ratpfs_remove(struct device_d __always_unused *dev) +static void ratpfs_remove(struct device __always_unused *dev) { pr_debug("%s\n", __func__); barebox_ratp_fs_mount(NULL); } -static struct fs_driver_d ratpfs_driver = { +static struct fs_driver ratpfs_driver = { .open = ratpfs_open, .close = ratpfs_close, .read = ratpfs_read, diff --git a/fs/smhfs.c b/fs/smhfs.c index 2e99b05979..5165bf9394 100644 --- a/fs/smhfs.c +++ b/fs/smhfs.c @@ -29,20 +29,20 @@ static int file_to_fd(const FILE *f) return (int)f->priv; } -static int smhfs_create(struct device_d __always_unused *dev, +static int smhfs_create(struct device __always_unused *dev, const char __always_unused *pathname, mode_t __always_unused mode) { return 0; } -static int smhfs_mkdir(struct device_d __always_unused *dev, +static int smhfs_mkdir(struct device __always_unused *dev, const char __always_unused *pathname) { return -ENOSYS; } -static int smhfs_rm(struct device_d __always_unused *dev, +static int smhfs_rm(struct device __always_unused *dev, const char *pathname) { /* Get rid of leading '/' */ @@ -54,14 +54,14 @@ static int smhfs_rm(struct device_d __always_unused *dev, return 0; } -static int smhfs_truncate(struct device_d __always_unused *dev, +static int smhfs_truncate(struct device __always_unused *dev, FILE __always_unused *f, loff_t __always_unused size) { return 0; } -static int smhfs_open(struct device_d __always_unused *dev, +static int smhfs_open(struct device __always_unused *dev, FILE *file, const char *filename) { int fd; @@ -82,7 +82,7 @@ error: return -semihosting_errno(); } -static int smhfs_close(struct device_d __always_unused *dev, +static int smhfs_close(struct device __always_unused *dev, FILE *f) { if (semihosting_close(file_to_fd(f))) @@ -91,7 +91,7 @@ static int smhfs_close(struct device_d __always_unused *dev, return 0; } -static int smhfs_write(struct device_d __always_unused *dev, +static int smhfs_write(struct device __always_unused *dev, FILE *f, const void *inbuf, size_t insize) { if (semihosting_write(file_to_fd(f), inbuf, insize)) @@ -100,7 +100,7 @@ static int smhfs_write(struct device_d __always_unused *dev, return insize; } -static int smhfs_read(struct device_d __always_unused *dev, +static int smhfs_read(struct device __always_unused *dev, FILE *f, void *buf, size_t insize) { if (!semihosting_read(file_to_fd(f), buf, insize)) @@ -109,7 +109,7 @@ static int smhfs_read(struct device_d __always_unused *dev, return -semihosting_errno(); } -static int smhfs_lseek(struct device_d __always_unused *dev, +static int smhfs_lseek(struct device __always_unused *dev, FILE *f, loff_t pos) { if (semihosting_seek(file_to_fd(f), pos)) @@ -118,13 +118,13 @@ static int smhfs_lseek(struct device_d __always_unused *dev, return 0; } -static DIR* smhfs_opendir(struct device_d __always_unused *dev, +static DIR* smhfs_opendir(struct device __always_unused *dev, const char __always_unused *pathname) { return NULL; } -static int smhfs_stat(struct device_d __always_unused *dev, +static int smhfs_stat(struct device __always_unused *dev, const char *filename, struct stat *s) { FILE file; @@ -138,17 +138,17 @@ static int smhfs_stat(struct device_d __always_unused *dev, return 0; } -static int smhfs_probe(struct device_d __always_unused *dev) +static int smhfs_probe(struct device __always_unused *dev) { /* TODO: Add provisions to detect if debugger is connected */ return 0; } -static void smhfs_remove(struct device_d __always_unused *dev) +static void smhfs_remove(struct device __always_unused *dev) { } -static struct fs_driver_d smhfs_driver = { +static struct fs_driver smhfs_driver = { .open = smhfs_open, .close = smhfs_close, .read = smhfs_read, diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig index 19b8297af6..af187a2a8a 100644 --- a/fs/squashfs/Kconfig +++ b/fs/squashfs/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + menuconfig FS_SQUASHFS bool prompt "squashfs support" diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index 81fc7e570d..59a78a24b0 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-y += squashfs.o obj-y += block.o obj-y += cache.o diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index 470536e589..f702f6c0a2 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c @@ -44,22 +44,6 @@ #include "squashfs_fs_i.h" #include "squashfs.h" -struct inode *iget_locked_squashfs(struct super_block *sb, unsigned long ino) -{ - struct inode *inode; - struct squashfs_inode_info *ei; - - ei = malloc(sizeof(struct squashfs_inode_info)); - inode = &ei->vfs_inode; - if (inode) { - inode->i_ino = ino; - inode->i_sb = sb; - inode->i_state = I_SYNC | I_NEW; - } - - return inode; -} - /* * Initialise VFS inode with the base inode information common to all * Squashfs inode types. Sqsh_ino contains the unswapped base inode @@ -94,7 +78,7 @@ static int squashfs_new_inode(struct super_block *sb, struct inode *inode, struct inode *squashfs_iget(struct super_block *sb, long long ino, unsigned int ino_number) { - struct inode *inode = iget_locked_squashfs(sb, ino_number); + struct inode *inode = iget_locked(sb, ino_number); int err; TRACE("Entered squashfs_iget\n"); @@ -124,7 +108,6 @@ int squashfs_read_inode(struct inode *inode, long long ino) int err, type, offset = SQUASHFS_INODE_OFFSET(ino); union squashfs_inode squashfs_ino; struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base; - int xattr_id = SQUASHFS_INVALID_XATTR; TRACE("Entered squashfs_read_inode: %lld\n", ino); @@ -213,7 +196,6 @@ int squashfs_read_inode(struct inode *inode, long long ino) frag_offset = 0; } - xattr_id = le32_to_cpu(sqsh_ino->xattr); inode->i_size = le64_to_cpu(sqsh_ino->file_size); inode->i_op = &squashfs_inode_ops; inode->i_mode |= S_IFREG; @@ -265,7 +247,6 @@ int squashfs_read_inode(struct inode *inode, long long ino) if (err < 0) goto failed_read; - xattr_id = le32_to_cpu(sqsh_ino->xattr); inode->i_size = le32_to_cpu(sqsh_ino->file_size); inode->i_op = &squashfs_dir_inode_ops; inode->i_fop = &squashfs_dir_ops; @@ -310,7 +291,6 @@ int squashfs_read_inode(struct inode *inode, long long ino) &offset, sizeof(xattr)); if (err < 0) goto failed_read; - xattr_id = le32_to_cpu(xattr); } TRACE("Symbolic link inode %x:%x, start_block %llx, offset " @@ -354,7 +334,6 @@ int squashfs_read_inode(struct inode *inode, long long ino) inode->i_mode |= S_IFCHR; else inode->i_mode |= S_IFBLK; - xattr_id = le32_to_cpu(sqsh_ino->xattr); rdev = le32_to_cpu(sqsh_ino->rdev); TRACE("Device inode %x:%x, rdev %x\n", @@ -391,7 +370,6 @@ int squashfs_read_inode(struct inode *inode, long long ino) inode->i_mode |= S_IFIFO; else inode->i_mode |= S_IFSOCK; - xattr_id = le32_to_cpu(sqsh_ino->xattr); break; } default: diff --git a/fs/squashfs/squashfs.c b/fs/squashfs/squashfs.c index 69451f7b84..f2e5769a19 100644 --- a/fs/squashfs/squashfs.c +++ b/fs/squashfs/squashfs.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <malloc.h> #include <driver.h> @@ -39,7 +41,7 @@ char *squashfs_devread(struct squashfs_sb_info *fs, int byte_offset, return buf; } -static void squashfs_set_rootarg(struct fs_device_d *fsdev) +static void squashfs_set_rootarg(struct fs_device *fsdev) { struct ubi_volume_desc *ubi_vol; struct ubi_volume_info vi = {}; @@ -88,9 +90,9 @@ static const struct super_operations squashfs_super_ops = { .destroy_inode = squashfs_destroy_inode, }; -static int squashfs_probe(struct device_d *dev) +static int squashfs_probe(struct device *dev) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; int ret; struct super_block *sb; @@ -101,6 +103,7 @@ static int squashfs_probe(struct device_d *dev) if (ret) goto err_out; + sb->s_op = &squashfs_super_ops; ret = squashfs_mount(fsdev, 0); if (ret) { @@ -110,8 +113,6 @@ static int squashfs_probe(struct device_d *dev) squashfs_set_rootarg(fsdev); - sb->s_op = &squashfs_super_ops; - return 0; err_out: @@ -119,9 +120,9 @@ err_out: return ret; } -static void squashfs_remove(struct device_d *dev) +static void squashfs_remove(struct device *dev) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; struct super_block *sb; fsdev = dev_to_fs_device(dev); @@ -130,7 +131,7 @@ static void squashfs_remove(struct device_d *dev) squashfs_put_super(sb); } -static int squashfs_open(struct device_d *dev, FILE *file, const char *filename) +static int squashfs_open(struct device *dev, FILE *file, const char *filename) { struct inode *inode = file->f_inode; struct squashfs_page *page; @@ -164,7 +165,7 @@ error: return -ENOMEM; } -static int squashfs_close(struct device_d *dev, FILE *f) +static int squashfs_close(struct device *dev, FILE *f) { struct squashfs_page *page = f->priv; int i; @@ -196,8 +197,8 @@ static int squashfs_read_buf(struct squashfs_page *page, int pos, void **buf) return 0; } -static int squashfs_read(struct device_d *_dev, FILE *f, void *buf, - size_t insize) +static int squashfs_read(struct device *_dev, FILE *f, void *buf, + size_t insize) { unsigned int size = insize; unsigned int pos = f->pos; @@ -250,7 +251,7 @@ struct squashfs_dir { char root_d_name[256]; }; -static struct fs_driver_d squashfs_driver = { +static struct fs_driver squashfs_driver = { .open = squashfs_open, .close = squashfs_close, .read = squashfs_read, diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 31c9bc454e..d22e83dc3c 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -17,7 +17,7 @@ * squashfs.h */ -#include <printk.h> +#include <linux/printk.h> #include <fs.h> #include <linux/fs.h> #include <linux/kernel.h> @@ -52,11 +52,10 @@ static inline struct squashfs_page *squashfs_page(struct page *page) #define WARNING(s, args...) pr_warn("SQUASHFS: "s, ## args) -struct inode *iget_locked_squashfs(struct super_block *sb, unsigned long ino); char *squashfs_devread(struct squashfs_sb_info *fs, int byte_offset, int byte_len); -extern int squashfs_mount(struct fs_device_d *fsdev, - int silent); +extern int squashfs_mount(struct fs_device *fsdev, + int silent); extern void squashfs_put_super(struct super_block *sb); /* block.c */ diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index 2b6f81d33a..c6fc37d48f 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h @@ -77,6 +77,6 @@ struct squashfs_sb_info { unsigned int inodes; int xattr_ids; struct cdev *cdev; - struct device_d *dev; + struct device *dev; }; #endif diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index e2b7b8d5a1..2e34c0e540 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -83,7 +83,6 @@ void squashfs_put_super(struct super_block *sb) } if (sb->s_root) { - kfree(squashfs_i(sb->s_root->d_inode)); kfree(sb->s_root); sb->s_root = NULL; } @@ -92,7 +91,7 @@ void squashfs_put_super(struct super_block *sb) static int squashfs_fill_super(struct super_block *sb, void *data, int silent) { struct squashfs_sb_info *msblk; - struct fs_device_d *fsdev = (struct fs_device_d *)data; + struct fs_device *fsdev = (struct fs_device *)data; struct squashfs_super_block *sblk = NULL; struct inode *root; long long root_inode; @@ -322,7 +321,7 @@ failed_mount: } -int squashfs_mount(struct fs_device_d *fsdev, int silent) +int squashfs_mount(struct fs_device *fsdev, int silent) { struct super_block *sb = &fsdev->sb; diff --git a/fs/tftp-selftest.h b/fs/tftp-selftest.h new file mode 100644 index 0000000000..2406ed329e --- /dev/null +++ b/fs/tftp-selftest.h @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ +// SPDX-FileCopyrightText: 2022 Enrico Scholz <enrico.scholz@sigma-chemnitz.de> + +#ifndef H_BAREBOX_FS_TFTP_SELFTEST_H +#define H_BAREBOX_FS_TFTP_SELFTEST_H + +#include <bselftest.h> + +#define _expect_fmt(_v) _Generic(_v, \ + void const *: "%p", \ + void *: "%p", \ + bool: "%d", \ + long int: "%lld", \ + long unsigned int: "%llu", \ + unsigned short: "%h", \ + signed int: "%d", \ + unsigned int: "%u") + +#define _expect_op(_a, _b, _op) \ + ({ \ + __typeof__(_a) __a = (_a); \ + __typeof__(_b) __b = (_b); \ + \ + total_tests++; \ + \ + if (!(__a _op __b)) { \ + char fmt[sizeof "%s:%d: failed: %XXX %XXX\n" # _op]; \ + strcpy(fmt, "%s:%d: failed: "); \ + strcat(fmt, _expect_fmt(__a)); \ + strcat(fmt, " " # _op " "); \ + strcat(fmt, _expect_fmt(__b)); \ + strcat(fmt, "\n"); \ + \ + failed_tests++; \ + printf(fmt, __func__, __LINE__, __a, __b); \ + } \ + }) + +#define _as_void(_p) ({ \ + void const *__res = (_p); \ + __res; \ + }) + +#define expect_eq(_a, _b) _expect_op(_a, _b, ==); +#define expect_ne(_a, _b) _expect_op(_a, _b, !=); +#define expect_it(_a) _expect_op(_a, true, ==); + +#define expect_err(_a) _expect_op(_a, 0, <); +#define expect_ok(_a) _expect_op(_a, 0, ==); + +/* _Generic() does not match 'void *' for typed pointers; cast them to raw + 'void *' first */ +#define expect_NULL(_a) _expect_op(_as_void(_a), NULL, ==); +#define expect_PTR(_a) _expect_op(_as_void(_a), NULL, !=); + +#endif /* H_BAREBOX_FS_TFTP_SELFTEST_H */ @@ -26,12 +26,18 @@ #include <libgen.h> #include <fcntl.h> #include <getopt.h> +#include <globalvar.h> #include <init.h> +#include <linux/bitmap.h> #include <linux/stat.h> #include <linux/err.h> +#include <linux/kernel.h> #include <kfifo.h> +#include <parseopt.h> #include <linux/sizes.h> +#include "tftp-selftest.h" + #define TFTP_PORT 69 /* Well known TFTP port number */ /* Seconds to wait before remote server is allowed to resend a lost packet */ @@ -58,21 +64,54 @@ #define STATE_WRQ 2 #define STATE_RDATA 3 #define STATE_WDATA 4 -#define STATE_OACK 5 +/* OACK from server has been received and we can begin to sent either the ACK + (for RRQ) or data (for WRQ) */ +#define STATE_START 5 #define STATE_WAITACK 6 #define STATE_LAST 7 #define STATE_DONE 8 #define TFTP_BLOCK_SIZE 512 /* default TFTP block size */ -#define TFTP_FIFO_SIZE 4096 +#define TFTP_MTU_SIZE 1432 /* MTU based block size */ +#define TFTP_MAX_WINDOW_SIZE CONFIG_FS_TFTP_MAX_WINDOW_SIZE + +/* allocate this number of blocks more than needed in the fifo */ +#define TFTP_EXTRA_BLOCKS 2 + +/* marker for an emtpy 'tftp_cache' */ +#define TFTP_CACHE_NO_ID (-1) #define TFTP_ERR_RESEND 1 +#if defined(DEBUG) || IS_ENABLED(CONFIG_SELFTEST_TFTP) +# define debug_assert(_cond) BUG_ON(!(_cond)) +#else +# define debug_assert(_cond) do { \ + if (!(_cond)) \ + __builtin_unreachable(); \ + } while (0) +#endif + +static int g_tftp_window_size = DIV_ROUND_UP(TFTP_MAX_WINDOW_SIZE, 2); + +struct tftp_block { + uint16_t id; + uint16_t len; + + struct list_head list; + uint8_t data[]; +}; + +struct tftp_cache { + struct list_head blocks; +}; + struct file_priv { struct net_connection *tftp_con; int push; uint16_t block; uint16_t last_block; + uint16_t ack_block; int state; int err; char *filename; @@ -82,28 +121,78 @@ struct file_priv { struct kfifo *fifo; void *buf; int blocksize; - int block_requested; + unsigned int windowsize; + bool is_getattr; + struct tftp_cache cache; }; struct tftp_priv { IPaddr_t server; }; -static int tftp_truncate(struct device_d *dev, FILE *f, loff_t size) +static inline bool is_block_before(uint16_t a, uint16_t b) +{ + return (int16_t)(b - a) > 0; +} + +static bool in_window(uint16_t block, uint16_t start, uint16_t end) +{ + /* handle the three cases: + - [ ......... | start | .. | BLOCK | .. | end | ......... ] + - [ ..| BLOCK | .. | end | ................. | start | .. ] + - [ ..| end | ................. | start | .. | BLOCK | .. ] + */ + return ((start <= block && block <= end) || + (block <= end && end <= start) || + (end <= start && start <= block)); +} + +static void tftp_window_cache_free(struct tftp_cache *cache) +{ + struct tftp_block *block, *tmp; + + list_for_each_entry_safe(block, tmp, &cache->blocks, list) + free(block); +} + +static int tftp_window_cache_insert(struct tftp_cache *cache, uint16_t id, + void const *data, size_t len) +{ + struct tftp_block *block, *new; + + list_for_each_entry(block, &cache->blocks, list) { + if (block->id == id) + return 0; + if (is_block_before(block->id, id)) + continue; + + break; + } + + new = xzalloc(sizeof(*new) + len); + memcpy(new->data, data, len); + new->id = id; + new->len = len; + list_add_tail(&new->list, &block->list); + + return 0; +} + +static int tftp_truncate(struct device *dev, FILE *f, loff_t size) { return 0; } -static char *tftp_states[] = { +static char const * const tftp_states[] = { [STATE_INVALID] = "INVALID", [STATE_RRQ] = "RRQ", [STATE_WRQ] = "WRQ", [STATE_RDATA] = "RDATA", [STATE_WDATA] = "WDATA", - [STATE_OACK] = "OACK", [STATE_WAITACK] = "WAITACK", [STATE_LAST] = "LAST", [STATE_DONE] = "DONE", + [STATE_START] = "START", }; static int tftp_send(struct file_priv *priv) @@ -112,6 +201,7 @@ static int tftp_send(struct file_priv *priv) int len = 0; uint16_t *s; unsigned char *pkt = net_udp_get_payload(priv->tftp_con); + unsigned int window_size; int ret; pr_vdebug("%s: state %s\n", __func__, tftp_states[priv->state]); @@ -119,6 +209,15 @@ static int tftp_send(struct file_priv *priv) switch (priv->state) { case STATE_RRQ: case STATE_WRQ: + if (priv->push || priv->is_getattr) + /* atm, windowsize is supported only for RRQ and there + is no need to request a full window when we are + just looking up file attributes */ + window_size = 1; + else + window_size = min_t(unsigned int, g_tftp_window_size, + TFTP_MAX_WINDOW_SIZE); + xp = pkt; s = (uint16_t *)pkt; if (priv->state == STATE_RRQ) @@ -131,30 +230,42 @@ static int tftp_send(struct file_priv *priv) "octet%c" "timeout%c" "%d%c" - "tsize%c" - "%lld%c" "blksize%c" - "1432", - priv->filename + 1, 0, - 0, - 0, - TIMEOUT, 0, - 0, - priv->filesize, 0, - 0); + "%u", + priv->filename + 1, '\0', + '\0', /* "octet" */ + '\0', /* "timeout" */ + TIMEOUT, '\0', + '\0', /* "blksize" */ + /* use only a minimal blksize for getattr + operations, */ + priv->is_getattr ? TFTP_BLOCK_SIZE : TFTP_MTU_SIZE); pkt++; + + if (!priv->push) + /* we do not know the filesize in WRQ requests and + 'priv->filesize' will always be zero */ + pkt += sprintf((unsigned char *)pkt, + "tsize%c%lld%c", + '\0', priv->filesize, + '\0'); + + if (window_size > 1) + pkt += sprintf((unsigned char *)pkt, + "windowsize%c%u%c", + '\0', window_size, + '\0'); + len = pkt - xp; break; case STATE_RDATA: - if (priv->block == priv->block_requested) - return 0; - case STATE_OACK: xp = pkt; s = (uint16_t *)pkt; *s++ = htons(TFTP_ACK); - *s++ = htons(priv->block); - priv->block_requested = priv->block; + *s++ = htons(priv->last_block); + priv->ack_block = priv->last_block; + priv->ack_block += priv->windowsize; pkt = (unsigned char *)s; len = pkt - xp; break; @@ -197,7 +308,6 @@ static int tftp_poll(struct file_priv *priv) if (is_timeout(priv->resend_timeout, TFTP_RESEND_TIMEOUT)) { printf("T "); priv->resend_timeout = get_time_ns(); - priv->block_requested = -1; return TFTP_ERR_RESEND; } @@ -212,7 +322,7 @@ static int tftp_poll(struct file_priv *priv) return 0; } -static void tftp_parse_oack(struct file_priv *priv, unsigned char *pkt, int len) +static int tftp_parse_oack(struct file_priv *priv, unsigned char *pkt, int len) { unsigned char *opt, *val, *s; @@ -229,14 +339,25 @@ static void tftp_parse_oack(struct file_priv *priv, unsigned char *pkt, int len) opt = s; val = s + strlen(s) + 1; if (val > s + len) - return; + break; if (!strcmp(opt, "tsize")) priv->filesize = simple_strtoull(val, NULL, 10); if (!strcmp(opt, "blksize")) priv->blocksize = simple_strtoul(val, NULL, 10); + if (!strcmp(opt, "windowsize")) + priv->windowsize = simple_strtoul(val, NULL, 10); pr_debug("OACK opt: %s val: %s\n", opt, val); s = val + strlen(val) + 1; } + + if (priv->blocksize > TFTP_MTU_SIZE || + priv->windowsize > TFTP_MAX_WINDOW_SIZE || + priv->windowsize == 0) { + pr_warn("tftp: invalid oack response\n"); + return -EINVAL; + } + + return 0; } static void tftp_timer_reset(struct file_priv *priv) @@ -244,10 +365,140 @@ static void tftp_timer_reset(struct file_priv *priv) priv->progress_timeout = priv->resend_timeout = get_time_ns(); } +static int tftp_allocate_transfer(struct file_priv *priv) +{ + debug_assert(!priv->fifo); + debug_assert(!priv->buf); + + /* multiplication is safe; both operands were checked in tftp_parse_oack() + and are small integers */ + priv->fifo = kfifo_alloc(priv->blocksize * + (priv->windowsize + TFTP_EXTRA_BLOCKS)); + if (!priv->fifo) + goto err; + + if (priv->push) { + priv->buf = xmalloc(priv->blocksize); + if (!priv->buf) { + kfifo_free(priv->fifo); + priv->fifo = NULL; + goto err; + } + } + + INIT_LIST_HEAD(&priv->cache.blocks); + + return 0; + +err: + priv->err = -ENOMEM; + priv->state = STATE_DONE; + + return priv->err; +} + +static void tftp_put_data(struct file_priv *priv, uint16_t block, + void const *pkt, size_t len) +{ + unsigned int sz; + + if (len > priv->blocksize) { + pr_warn("tftp: oversized packet (%zu > %d) received\n", + len, priv->blocksize); + return; + } + + priv->last_block = block; + + sz = kfifo_put(priv->fifo, pkt, len); + + if (sz != len) { + pr_err("tftp: not enough room in kfifo (only %u out of %zu written)\n", + sz, len); + priv->err = -ENOMEM; + priv->state = STATE_DONE; + } else if (len < priv->blocksize) { + tftp_send(priv); + priv->err = 0; + priv->state = STATE_DONE; + } +} + +static void tftp_apply_window_cache(struct file_priv *priv) +{ + struct tftp_cache *cache = &priv->cache; + + while (1) { + struct tftp_block *block; + + /* can be changed by tftp_put_data() below and must be + checked in each loop */ + if (priv->state != STATE_RDATA) + return; + + if (list_empty(&cache->blocks)) + return; + + block = list_first_entry(&cache->blocks, struct tftp_block, list); + + if (is_block_before(block->id, priv->last_block + 1)) { + /* shouldn't happen, but be sure */ + list_del(&block->list); + free(block); + continue; + } + + if (block->id != (uint16_t)(priv->last_block + 1)) + return; + + tftp_put_data(priv, block->id, block->data, block->len); + + list_del(&block->list); + + free(block); + } +} + +static void tftp_handle_data(struct file_priv *priv, uint16_t block, + void const *data, size_t len) +{ + uint16_t exp_block; + int rc; + + exp_block = priv->last_block + 1; + + if (exp_block == block) { + /* datagram over network is the expected one; put it in the + fifo directly and try to apply cached items then */ + tftp_timer_reset(priv); + tftp_put_data(priv, block, data, len); + tftp_apply_window_cache(priv); + } else if (!in_window(block, exp_block, priv->ack_block)) { + /* completely unexpected and unrelated to actual window; + ignore the packet. */ + printf("B"); + if (g_tftp_window_size > 1) + pr_warn_once("Unexpected packet. global.tftp.windowsize set too high?\n"); + } else { + /* The 'rc < 0' below happens e.g. when datagrams in the first + part of the transfer window are dropped. + + TODO: this will usually result in a timeout + (TFTP_RESEND_TIMEOUT). It should be possible to bypass + this timeout by acknowledging the last packet (e.g. by + doing 'priv->ack_block = priv->last_block' here). */ + rc = tftp_window_cache_insert(&priv->cache, block, data, len); + if (rc < 0) + printf("M"); + } +} + static void tftp_recv(struct file_priv *priv, uint8_t *pkt, unsigned len, uint16_t uh_sport) { uint16_t opcode; + uint16_t block; + int rc; /* according to RFC1350 minimal tftp packet length is 4 bytes */ if (len < 4) @@ -270,75 +521,80 @@ static void tftp_recv(struct file_priv *priv, if (!priv->push) break; - priv->block = ntohs(*(uint16_t *)pkt); - if (priv->block != priv->last_block) { - pr_vdebug("ack %d != %d\n", priv->block, priv->last_block); + block = ntohs(*(uint16_t *)pkt); + if (block != priv->last_block) { + pr_vdebug("ack %d != %d\n", block, priv->last_block); break; } - priv->block++; + switch (priv->state) { + case STATE_WRQ: + priv->tftp_con->udp->uh_dport = uh_sport; + priv->state = STATE_START; + break; - tftp_timer_reset(priv); + case STATE_WAITACK: + priv->state = STATE_WDATA; + break; - if (priv->state == STATE_LAST) { + case STATE_LAST: priv->state = STATE_DONE; break; + + default: + pr_warn("ACK packet in %s state\n", + tftp_states[priv->state]); + goto ack_out; } - priv->tftp_con->udp->uh_dport = uh_sport; - priv->state = STATE_WDATA; + + priv->block = block + 1; + tftp_timer_reset(priv); + + ack_out: break; case TFTP_OACK: - tftp_parse_oack(priv, pkt, len); + if (priv->state != STATE_RRQ && priv->state != STATE_WRQ) { + pr_warn("OACK packet in %s state\n", + tftp_states[priv->state]); + break; + } + priv->tftp_con->udp->uh_dport = uh_sport; - if (priv->push) { - /* send first block */ - priv->state = STATE_WDATA; - priv->block = 1; - } else { - /* send ACK */ - priv->state = STATE_OACK; - priv->block = 0; - tftp_send(priv); + if (tftp_parse_oack(priv, pkt, len) < 0) { + priv->err = -EINVAL; + priv->state = STATE_DONE; + break; } + priv->state = STATE_START; break; + case TFTP_DATA: len -= 2; - priv->block = ntohs(*(uint16_t *)pkt); + block = ntohs(*(uint16_t *)pkt); - if (priv->state == STATE_RRQ || priv->state == STATE_OACK) { - /* first block received */ - priv->state = STATE_RDATA; + if (priv->state == STATE_RRQ) { + /* first block received; entered only with non rfc + 2347 (TFTP Option extension) compliant servers */ priv->tftp_con->udp->uh_dport = uh_sport; + priv->state = STATE_RDATA; priv->last_block = 0; + priv->ack_block = priv->windowsize; - if (priv->block != 1) { /* Assertion */ - pr_err("error: First block is not block 1 (%d)\n", - priv->block); - priv->err = -EINVAL; - priv->state = STATE_DONE; + rc = tftp_allocate_transfer(priv); + if (rc < 0) break; - } } - if (priv->block == priv->last_block) - /* Same block again; ignore it. */ + if (priv->state != STATE_RDATA) { + pr_warn("DATA packet in %s state\n", + tftp_states[priv->state]); break; - - priv->last_block = priv->block; - - tftp_timer_reset(priv); - - kfifo_put(priv->fifo, pkt + 2, len); - - if (len < priv->blocksize) { - tftp_send(priv); - priv->err = 0; - priv->state = STATE_DONE; } + tftp_handle_data(priv, block, pkt + 2, len); break; case TFTP_ERROR: @@ -369,13 +625,39 @@ static void tftp_handler(void *ctx, char *packet, unsigned len) tftp_recv(priv, pkt, net_eth_to_udplen(packet), udp->uh_sport); } -static struct file_priv *tftp_do_open(struct device_d *dev, - int accmode, struct dentry *dentry) +static int tftp_start_transfer(struct file_priv *priv) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + int rc; + + rc = tftp_allocate_transfer(priv); + if (rc < 0) + /* function sets 'priv->state = STATE_DONE' and 'priv->err' in + error case */ + return rc; + + if (priv->push) { + /* send first block */ + priv->state = STATE_WDATA; + priv->block = 1; + } else { + /* send ACK */ + priv->state = STATE_RDATA; + priv->last_block = 0; + tftp_send(priv); + } + + return 0; +} + +static struct file_priv *tftp_do_open(struct device *dev, + int accmode, struct dentry *dentry, + bool is_getattr) +{ + struct fs_device *fsdev = dev_to_fs_device(dev); struct file_priv *priv; struct tftp_priv *tpriv = dev->priv; int ret; + unsigned short port = TFTP_PORT; priv = xzalloc(sizeof(*priv)); @@ -397,59 +679,87 @@ static struct file_priv *tftp_do_open(struct device_d *dev, priv->err = -EINVAL; priv->filename = dpath(dentry, fsdev->vfsmount.mnt_root); priv->blocksize = TFTP_BLOCK_SIZE; - priv->block_requested = -1; + priv->windowsize = 1; + priv->is_getattr = is_getattr; - priv->fifo = kfifo_alloc(TFTP_FIFO_SIZE); - if (!priv->fifo) { - ret = -ENOMEM; - goto out; - } + parseopt_hu(fsdev->options, "port", &port); - priv->tftp_con = net_udp_new(tpriv->server, TFTP_PORT, tftp_handler, - priv); + priv->tftp_con = net_udp_new(tpriv->server, port, tftp_handler, priv); if (IS_ERR(priv->tftp_con)) { ret = PTR_ERR(priv->tftp_con); - goto out1; + goto out; } ret = tftp_send(priv); if (ret) - goto out2; + goto out1; tftp_timer_reset(priv); - while (priv->state != STATE_RDATA && - priv->state != STATE_DONE && - priv->state != STATE_WDATA) { - ret = tftp_poll(priv); - if (ret == TFTP_ERR_RESEND) - tftp_send(priv); - if (ret < 0) - goto out2; - } - if (priv->state == STATE_DONE && priv->err) { - ret = priv->err; - goto out2; - } + /* - 'ret < 0' ... error + - 'ret == 0' ... further tftp_poll() required + - 'ret == 1' ... startup finished */ + do { + switch (priv->state) { + case STATE_DONE: + /* branch is entered in two situations: + - non rfc 2347 compliant servers finished the + transfer by sending a small file + - some error occurred */ + if (priv->err < 0) + ret = priv->err; + else + ret = 1; + break; - priv->buf = xmalloc(priv->blocksize); + case STATE_START: + ret = tftp_start_transfer(priv); + if (!ret) + ret = 1; + break; + + case STATE_RDATA: + /* first data block of non rfc 2347 servers */ + ret = 1; + break; + + case STATE_RRQ: + case STATE_WRQ: + ret = tftp_poll(priv); + if (ret == TFTP_ERR_RESEND) { + tftp_send(priv); + ret = 0; + } + break; + + default: + debug_assert(false); + break; + } + } while (ret == 0); + + if (ret < 0) + goto out1; return priv; -out2: - net_unregister(priv->tftp_con); out1: - kfifo_free(priv->fifo); + net_unregister(priv->tftp_con); out: + if (priv->fifo) + kfifo_free(priv->fifo); + + free(priv->filename); + free(priv->buf); free(priv); return ERR_PTR(ret); } -static int tftp_open(struct device_d *dev, FILE *file, const char *filename) +static int tftp_open(struct device *dev, FILE *file, const char *filename) { struct file_priv *priv; - priv = tftp_do_open(dev, file->flags, file->dentry); + priv = tftp_do_open(dev, file->flags, file->dentry, false); if (IS_ERR(priv)) return PTR_ERR(priv); @@ -489,6 +799,7 @@ static int tftp_do_close(struct file_priv *priv) } net_unregister(priv->tftp_con); + tftp_window_cache_free(&priv->cache); kfifo_free(priv->fifo); free(priv->filename); free(priv->buf); @@ -497,15 +808,15 @@ static int tftp_do_close(struct file_priv *priv) return 0; } -static int tftp_close(struct device_d *dev, FILE *f) +static int tftp_close(struct device *dev, FILE *f) { struct file_priv *priv = f->priv; return tftp_do_close(priv); } -static int tftp_write(struct device_d *_dev, FILE *f, const void *inbuf, - size_t insize) +static int tftp_write(struct device *_dev, FILE *f, const void *inbuf, + size_t insize) { struct file_priv *priv = f->priv; size_t size, now; @@ -540,11 +851,11 @@ static int tftp_write(struct device_d *_dev, FILE *f, const void *inbuf, return insize; } -static int tftp_read(struct device_d *dev, FILE *f, void *buf, size_t insize) +static int tftp_read(struct device *dev, FILE *f, void *buf, size_t insize) { struct file_priv *priv = f->priv; size_t outsize = 0, now; - int ret; + int ret = 0; pr_vdebug("%s %zu\n", __func__, insize); @@ -553,23 +864,34 @@ static int tftp_read(struct device_d *dev, FILE *f, void *buf, size_t insize) outsize += now; buf += now; insize -= now; - if (priv->state == STATE_DONE) - return outsize; - if (TFTP_FIFO_SIZE - kfifo_len(priv->fifo) >= priv->blocksize) + if (priv->state == STATE_DONE) { + ret = priv->err; + break; + } + + /* send the ACK only when fifo has been nearly depleted; else, + when tftp_read() is called with small 'insize' values, it + is possible that there is read more data from the network + than consumed by kfifo_get() and the fifo overflows */ + if (priv->last_block == priv->ack_block && + kfifo_len(priv->fifo) <= TFTP_EXTRA_BLOCKS * priv->blocksize) tftp_send(priv); ret = tftp_poll(priv); if (ret == TFTP_ERR_RESEND) tftp_send(priv); if (ret < 0) - return ret; + break; } + if (ret < 0) + return ret; + return outsize; } -static int tftp_lseek(struct device_d *dev, FILE *f, loff_t pos) +static int tftp_lseek(struct device *dev, FILE *f, loff_t pos) { /* We cannot seek backwards without reloading or caching the file */ loff_t f_pos = f->pos; @@ -660,12 +982,12 @@ static struct dentry *tftp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct inode *inode; struct file_priv *priv; loff_t filesize; - priv = tftp_do_open(&fsdev->dev, O_RDONLY, dentry); + priv = tftp_do_open(&fsdev->dev, O_RDONLY, dentry, true); if (IS_ERR(priv)) return NULL; @@ -695,9 +1017,9 @@ static const struct inode_operations tftp_dir_inode_operations = static const struct super_operations tftp_ops; -static int tftp_probe(struct device_d *dev) +static int tftp_probe(struct device *dev) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct tftp_priv *priv = xzalloc(sizeof(struct tftp_priv)); struct super_block *sb = &fsdev->sb; struct inode *inode; @@ -724,14 +1046,14 @@ err: return ret; } -static void tftp_remove(struct device_d *dev) +static void tftp_remove(struct device *dev) { struct tftp_priv *priv = dev->priv; free(priv); } -static struct fs_driver_d tftp_driver = { +static struct fs_driver tftp_driver = { .open = tftp_open, .close = tftp_close, .read = tftp_read, @@ -748,6 +1070,8 @@ static struct fs_driver_d tftp_driver = { static int tftp_init(void) { + globalvar_add_simple_int("tftp.windowsize", &g_tftp_window_size, "%u"); + return register_fs_driver(&tftp_driver); } coredevice_initcall(tftp_init); diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig index 889a2be97a..15fcec4459 100644 --- a/fs/ubifs/Kconfig +++ b/fs/ubifs/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + menuconfig FS_UBIFS bool depends on MTD_UBI @@ -15,4 +17,9 @@ config FS_UBIFS_COMPRESSION_ZLIB select ZLIB prompt "ZLIB compression support" +config FS_UBIFS_COMPRESSION_ZSTD + bool + select ZSTD_DECOMPRESS + prompt "ZSTD compression support" + endif diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile index d8c4b2299e..7a1ce4e8fc 100644 --- a/fs/ubifs/Makefile +++ b/fs/ubifs/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-y += ubifs.o io.o super.o sb.o master.o obj-y += scan.o dir.o misc.o obj-y += tnc.o tnc_misc.o debug.o diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c index ea88926163..113c2cf755 100644 --- a/fs/ubifs/scan.c +++ b/fs/ubifs/scan.c @@ -244,7 +244,7 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs, if (len > 8192) len = 8192; ubifs_err(c, "first %d bytes from LEB %d:%d", len, lnum, offs); - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1); + print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1); } /** diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index b48e21fae6..564ac950eb 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -86,11 +86,6 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode) return 1; } - if (ui->compr_type >= UBIFS_COMPR_TYPES_CNT) { - ubifs_err(c, "unknown compression type %d", ui->compr_type); - return 2; - } - if (ui->xattr_names + ui->xattr_cnt > XATTR_LIST_MAX) return 3; @@ -1212,9 +1207,10 @@ out_shrinker: /* late_initcall to let compressors initialize first */ late_initcall(ubifs_init); -int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent) +int ubifs_get_super(struct device *dev, struct ubi_volume_desc *ubi, + int silent) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct super_block *sb; struct ubifs_info *c; int err; diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 2d7327ad84..72f9b817d8 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -1935,7 +1935,12 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n) do { ubifs_assert(c, !ubifs_zn_obsolete(znode)); - ubifs_assert(c, ubifs_zn_dirty(znode)); + /* + * This assertion is invalid in barebox due to the shortcuts we take + * in our readonly implementation. + * + * ubifs_assert(c, ubifs_zn_dirty(znode)); + */ zp = znode->parent; n = znode->iip; diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h index 8b7c184401..697b1b8906 100644 --- a/fs/ubifs/ubifs-media.h +++ b/fs/ubifs/ubifs-media.h @@ -348,12 +348,14 @@ enum { * UBIFS_COMPR_NONE: no compression * UBIFS_COMPR_LZO: LZO compression * UBIFS_COMPR_ZLIB: ZLIB compression + * UBIFS_COMPR_ZSTD: ZSTD compression * UBIFS_COMPR_TYPES_CNT: count of supported compression types */ enum { UBIFS_COMPR_NONE, UBIFS_COMPR_LZO, UBIFS_COMPR_ZLIB, + UBIFS_COMPR_ZSTD, UBIFS_COMPR_TYPES_CNT, }; diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c index fd35619246..ad288f4daa 100644 --- a/fs/ubifs/ubifs.c +++ b/fs/ubifs/ubifs.c @@ -19,14 +19,13 @@ #include <magicvar.h> #include <linux/stat.h> #include <linux/zlib.h> +#include <linux/zstd.h> #include <linux/mtd/mtd.h> #include "ubifs.h" #include <linux/err.h> -struct task_struct *current; - struct ubifs_priv { struct cdev *cdev; struct ubi_volume_desc *ubi; @@ -35,6 +34,7 @@ struct ubifs_priv { static struct z_stream_s ubifs_zlib_stream; +static ZSTD_DCtx *ubifs_zstd_cctx; /* compress.c */ @@ -46,7 +46,30 @@ static struct z_stream_s ubifs_zlib_stream; static int gzip_decompress(const unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len) { - return deflate_decompress(&ubifs_zlib_stream, in, in_len, out, out_len); + unsigned int olen; + int ret; + + ret = deflate_decompress(&ubifs_zlib_stream, in, in_len, out, &olen); + + *out_len = olen; + + return ret; +} +#endif + +#if defined(CONFIG_ZSTD_DECOMPRESS) +static int zstd_decompress(const unsigned char *in, size_t in_len, + unsigned char *out, size_t *out_len) +{ + size_t olen; + + olen = ZSTD_decompressDCtx(ubifs_zstd_cctx, out, *out_len, in, in_len); + if (ZSTD_isError(olen)) + return -EINVAL; + + *out_len = olen; + + return 0; } #endif @@ -76,6 +99,15 @@ static struct ubifs_compressor zlib_compr = { #endif }; +static struct ubifs_compressor zstd_compr = { + .compr_type = UBIFS_COMPR_ZSTD, + .name = "zstd", +#ifdef CONFIG_ZSTD_DECOMPRESS + .capi_name = "zstd", + .decompress = zstd_decompress, +#endif +}; + /* All UBIFS compressors */ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; @@ -100,7 +132,8 @@ static inline struct crypto_comp i++; continue; } - if (strncmp(alg_name, comp->capi_name, strlen(alg_name)) == 0) { + if (comp->capi_name && + strncmp(alg_name, comp->capi_name, strlen(alg_name)) == 0) { ptr->compressor = i; return ptr; } @@ -240,6 +273,10 @@ int __init ubifs_compressors_init(void) if (err) return err; + err = compr_init(&zstd_compr); + if (err) + return err; + err = compr_init(&none_compr); if (err) return err; @@ -303,7 +340,7 @@ struct ubifs_file { struct ubifs_data_node *dn; }; -static int ubifs_open(struct device_d *dev, FILE *file, const char *filename) +static int ubifs_open(struct device *dev, FILE *file, const char *filename) { struct inode *inode = file->f_inode; struct ubifs_file *uf; @@ -321,7 +358,7 @@ static int ubifs_open(struct device_d *dev, FILE *file, const char *filename) return 0; } -static int ubifs_close(struct device_d *dev, FILE *f) +static int ubifs_close(struct device *dev, FILE *f) { struct ubifs_file *uf = f->priv; @@ -347,7 +384,7 @@ static int ubifs_get_block(struct ubifs_file *uf, unsigned int pos) return 0; } -static int ubifs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) +static int ubifs_read(struct device *_dev, FILE *f, void *buf, size_t insize) { struct ubifs_file *uf = f->priv; unsigned int pos = f->pos; @@ -394,7 +431,8 @@ static int ubifs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize) return insize; } -static void ubifs_set_rootarg(struct ubifs_priv *priv, struct fs_device_d *fsdev) +static void ubifs_set_rootarg(struct ubifs_priv *priv, + struct fs_device *fsdev) { struct ubi_volume_info vi = {}; struct ubi_device_info di = {}; @@ -414,9 +452,9 @@ static void ubifs_set_rootarg(struct ubifs_priv *priv, struct fs_device_d *fsdev free(str); } -static int ubifs_probe(struct device_d *dev) +static int ubifs_probe(struct device *dev) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct ubifs_priv *priv = xzalloc(sizeof(struct ubifs_priv)); int ret; @@ -430,8 +468,7 @@ static int ubifs_probe(struct device_d *dev) priv->ubi = ubi_open_volume_cdev(priv->cdev, UBI_READONLY); if (IS_ERR(priv->ubi)) { - dev_err(dev, "failed to open ubi volume: %s\n", - strerrorp(priv->ubi)); + dev_err(dev, "failed to open ubi volume: %pe\n", priv->ubi); ret = PTR_ERR(priv->ubi); goto err_free; } @@ -452,7 +489,7 @@ err_free: return ret; } -static void ubifs_remove(struct device_d *dev) +static void ubifs_remove(struct device *dev) { struct ubifs_priv *priv = dev->priv; struct super_block *sb = priv->sb; @@ -466,7 +503,7 @@ static void ubifs_remove(struct device_d *dev) free(priv); } -static struct fs_driver_d ubifs_driver = { +static struct fs_driver ubifs_driver = { .open = ubifs_open, .close = ubifs_close, .read = ubifs_read, @@ -495,6 +532,21 @@ static int zlib_decomp_init(void) return 0; } +static int zstd_decomp_init(void) +{ + const size_t wksp_size = ZSTD_DCtxWorkspaceBound(); + void *wksp = malloc(wksp_size); + + if (!wksp) + return -ENOMEM; + + ubifs_zstd_cctx = ZSTD_initDCtx(wksp, wksp_size); + if (!ubifs_zstd_cctx) + return -EINVAL; + + return 0; +} + int ubifs_allow_encrypted; int ubifs_allow_authenticated_unauthenticated; @@ -508,6 +560,12 @@ static int ubifs_init(void) return ret; } + if (IS_ENABLED(CONFIG_ZSTD_DECOMPRESS)) { + ret = zstd_decomp_init(); + if (ret) + return ret; + } + globalvar_add_simple_bool("ubifs.allow_encrypted", &ubifs_allow_encrypted); globalvar_add_simple_bool("ubifs.allow_authenticated_unauthenticated", &ubifs_allow_authenticated_unauthenticated); @@ -517,8 +575,7 @@ static int ubifs_init(void) coredevice_initcall(ubifs_init); -BAREBOX_MAGICVAR_NAMED(global_ubifs_allow_encrypted, global.ubifs.allow_encrypted, - "If true, allow to mount UBIFS with encrypted files"); -BAREBOX_MAGICVAR_NAMED(global_ubifs_allow_authenticated_unauthenticated, - global.ubifs.allow_authenticated_unauthenticated, - "If true, allow to mount authenticated UBIFS images without doing authentication"); +BAREBOX_MAGICVAR(global.ubifs.allow_encrypted, + "If true, allow to mount UBIFS with encrypted files"); +BAREBOX_MAGICVAR(global.ubifs.allow_authenticated_unauthenticated, + "If true, allow to mount authenticated UBIFS images without doing authentication"); diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index bffaa26fb3..598614efea 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -1512,7 +1512,7 @@ struct ubifs_info { struct rb_root size_tree; struct ubifs_mount_opts mount_opts; - struct device_d *dev; + struct device *dev; struct ubifs_debug_info *dbg; }; @@ -2060,7 +2060,8 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len, /* barebox specific */ void ubifs_umount(struct ubifs_info *c); /* barebox specific */ -int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent); +int ubifs_get_super(struct device *dev, struct ubi_volume_desc *ubi, + int silent); #ifndef CONFIG_UBIFS_FS_ENCRYPTION static inline int ubifs_encrypt(const struct inode *inode, diff --git a/fs/ubootvarfs.c b/fs/ubootvarfs.c index 475e4b7a79..32cf574e57 100644 --- a/fs/ubootvarfs.c +++ b/fs/ubootvarfs.c @@ -148,7 +148,7 @@ static struct dentry *ubootvarfs_lookup(struct inode *dir, unsigned int flags) { struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct ubootvarfs_data *data = fsdev->dev.priv; struct ubootvarfs_var *var; struct inode *inode; @@ -259,6 +259,7 @@ static int ubootvarfs_unlink(struct inode *dir, struct dentry *dentry) list_del(&var->list); free(var); + node->var = NULL; } return simple_unlink(dir, dentry); @@ -268,7 +269,7 @@ static int ubootvarfs_create(struct inode *dir, struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct ubootvarfs_data *data = fsdev->dev.priv; struct inode *inode; struct ubootvarfs_var *var; @@ -310,7 +311,7 @@ static const struct inode_operations ubootvarfs_dir_inode_operations = { static struct inode *ubootvarfs_alloc_inode(struct super_block *sb) { struct ubootvarfs_inode *node; - struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb); + struct fs_device *fsdev = container_of(sb, struct fs_device, sb); struct ubootvarfs_data *data = fsdev->dev.priv; node = xzalloc(sizeof(*node)); @@ -332,7 +333,7 @@ static const struct super_operations ubootvarfs_ops = { .destroy_inode = ubootvarfs_destroy_inode, }; -static int ubootvarfs_io(struct device_d *dev, FILE *f, void *buf, +static int ubootvarfs_io(struct device *dev, FILE *f, void *buf, size_t insize, bool read) { struct inode *inode = f->f_inode; @@ -347,19 +348,19 @@ static int ubootvarfs_io(struct device_d *dev, FILE *f, void *buf, return insize; } -static int ubootvarfs_read(struct device_d *dev, FILE *f, void *buf, +static int ubootvarfs_read(struct device *dev, FILE *f, void *buf, size_t insize) { return ubootvarfs_io(dev, f, buf, insize, true); } -static int ubootvarfs_write(struct device_d *dev, FILE *f, const void *buf, +static int ubootvarfs_write(struct device *dev, FILE *f, const void *buf, size_t insize) { return ubootvarfs_io(dev, f, (void *)buf, insize, false); } -static int ubootvarfs_truncate(struct device_d *dev, FILE *f, loff_t size) +static int ubootvarfs_truncate(struct device *dev, FILE *f, loff_t size) { struct inode *inode = f->f_inode; struct ubootvarfs_inode *node = inode_to_node(inode); @@ -422,11 +423,11 @@ static void ubootvarfs_parse(struct ubootvarfs_data *data, char *blob, data->end = blob; } -static int ubootvarfs_probe(struct device_d *dev) +static int ubootvarfs_probe(struct device *dev) { struct inode *inode; struct ubootvarfs_data *data = xzalloc(sizeof(*data)); - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct super_block *sb = &fsdev->sb; struct stat s; void *map; @@ -471,7 +472,7 @@ free_data: return ret; } -static void ubootvarfs_remove(struct device_d *dev) +static void ubootvarfs_remove(struct device *dev) { struct ubootvarfs_data *data = dev->priv; @@ -480,7 +481,7 @@ static void ubootvarfs_remove(struct device_d *dev) free(data); } -static struct fs_driver_d ubootvarfs_driver = { +static struct fs_driver ubootvarfs_driver = { .truncate = ubootvarfs_truncate, .read = ubootvarfs_read, .write = ubootvarfs_write, diff --git a/fs/uimagefs.c b/fs/uimagefs.c index 72641c58b5..735a35e500 100644 --- a/fs/uimagefs.c +++ b/fs/uimagefs.c @@ -9,7 +9,6 @@ #include <fs.h> #include <errno.h> #include <fcntl.h> -#include <fs.h> #include <malloc.h> #include <init.h> #include <linux/stat.h> @@ -69,7 +68,7 @@ static struct uimagefs_handle_data *uimagefs_get_by_name( return NULL; } -static int uimagefs_open(struct device_d *dev, FILE *file, const char *filename) +static int uimagefs_open(struct device *dev, FILE *file, const char *filename) { struct uimagefs_handle *priv = dev->priv; struct uimagefs_handle_data *d; @@ -95,7 +94,7 @@ static int uimagefs_open(struct device_d *dev, FILE *file, const char *filename) return 0; } -static int uimagefs_close(struct device_d *dev, FILE *file) +static int uimagefs_close(struct device *dev, FILE *file) { struct uimagefs_handle_data *d = file->priv; @@ -104,7 +103,8 @@ static int uimagefs_close(struct device_d *dev, FILE *file) return 0; } -static int uimagefs_read(struct device_d *dev, FILE *file, void *buf, size_t insize) +static int uimagefs_read(struct device *dev, FILE *file, void *buf, + size_t insize) { struct uimagefs_handle_data *d = file->priv; @@ -116,7 +116,7 @@ static int uimagefs_read(struct device_d *dev, FILE *file, void *buf, size_t ins } } -static int uimagefs_lseek(struct device_d *dev, FILE *file, loff_t pos) +static int uimagefs_lseek(struct device *dev, FILE *file, loff_t pos) { struct uimagefs_handle_data *d = file->priv; @@ -128,7 +128,7 @@ static int uimagefs_lseek(struct device_d *dev, FILE *file, loff_t pos) return 0; } -static DIR *uimagefs_opendir(struct device_d *dev, const char *pathname) +static DIR *uimagefs_opendir(struct device *dev, const char *pathname) { struct uimagefs_handle *priv = dev->priv; DIR *dir; @@ -143,7 +143,7 @@ static DIR *uimagefs_opendir(struct device_d *dev, const char *pathname) return dir; } -static struct dirent *uimagefs_readdir(struct device_d *dev, DIR *dir) +static struct dirent *uimagefs_readdir(struct device *dev, DIR *dir) { struct uimagefs_handle *priv = dev->priv; struct uimagefs_handle_data *d = dir->priv; @@ -156,13 +156,14 @@ static struct dirent *uimagefs_readdir(struct device_d *dev, DIR *dir) return &dir->d; } -static int uimagefs_closedir(struct device_d *dev, DIR *dir) +static int uimagefs_closedir(struct device *dev, DIR *dir) { free(dir); return 0; } -static int uimagefs_stat(struct device_d *dev, const char *filename, struct stat *s) +static int uimagefs_stat(struct device *dev, const char *filename, + struct stat *s) { struct uimagefs_handle *priv = dev->priv; struct uimagefs_handle_data *d; @@ -180,7 +181,7 @@ static int uimagefs_stat(struct device_d *dev, const char *filename, struct stat return 0; } -static int uimagefs_ioctl(struct device_d *dev, FILE *f, int request, void *buf) +static int uimagefs_ioctl(struct device *dev, FILE *f, int request, void *buf) { struct uimagefs_handle *priv = dev->priv; @@ -192,7 +193,7 @@ static int uimagefs_ioctl(struct device_d *dev, FILE *f, int request, void *buf) return 0; } -static void uimagefs_remove(struct device_d *dev) +static void uimagefs_remove(struct device *dev) { struct uimagefs_handle *priv = dev->priv; struct uimagefs_handle_data *d, *tmp; @@ -296,28 +297,24 @@ static int uimagefs_add_data_entry(struct uimagefs_handle *priv, size_t offset, return 0; } -#if defined(CONFIG_TIMESTAMP) static int uimagefs_add_time(struct uimagefs_handle *priv) { struct image_header *header = &priv->header; - struct rtc_time tm; - char *val; - to_tm(header->ih_time, &tm); - val = basprintf("%4d-%02d-%02d %2d:%02d:%02d UTC", - tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); + if (IS_ENABLED(CONFIG_TIMESTAMP)) { + struct rtc_time tm; + char *val; - return uimagefs_add_str(priv, UIMAGEFS_TIME, val); -} -#else -static int uimagefs_add_time(struct uimagefs_handle *priv) -{ - struct image_header *header = &priv->header; + to_tm(header->ih_time, &tm); + val = basprintf("%4d-%02d-%02d %2d:%02d:%02d UTC", + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + return uimagefs_add_str(priv, UIMAGEFS_TIME, val); + } return uimagefs_add_hex(priv, UIMAGEFS_TIME, header->ih_time); } -#endif static int uimagefs_add_os(struct uimagefs_handle *priv) { @@ -374,7 +371,7 @@ static int __uimage_open(struct uimagefs_handle *priv) fd = open(filename, O_RDONLY); if (fd < 0) { - printf("could not open: %s\n", errno_str()); + printf("could not open: %m\n"); return fd; } @@ -382,7 +379,7 @@ static int __uimage_open(struct uimagefs_handle *priv) ret = read(fd, header, sizeof(*header)); if (ret < 0) { - printf("could not read: %s\n", errno_str()); + printf("could not read: %m\n"); goto err_out; } offset += sizeof(*header); @@ -494,9 +491,9 @@ err_out: return ret; } -static int uimagefs_probe(struct device_d *dev) +static int uimagefs_probe(struct device *dev) { - struct fs_device_d *fsdev = dev_to_fs_device(dev); + struct fs_device *fsdev = dev_to_fs_device(dev); struct uimagefs_handle *priv; int ret = 0; @@ -519,7 +516,7 @@ err: return ret; } -static struct fs_driver_d uimagefs_driver = { +static struct fs_driver uimagefs_driver = { .open = uimagefs_open, .close = uimagefs_close, .read = uimagefs_read, |