diff options
Diffstat (limited to 'fs')
87 files changed, 2701 insertions, 1641 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 f13dc97c32..6160ef4e1a 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -1,10 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-$(CONFIG_FS_CRAMFS) += cramfs/ obj-$(CONFIG_FS_EXT4) += ext4/ obj-$(CONFIG_FS_RAMFS) += ramfs.o obj-y += devfs-core.o obj-$(CONFIG_FS_LEGACY) += legacy.o obj-$(CONFIG_FS_DEVFS) += devfs.o -obj-$(CONFIG_FS_FAT) += fat/ +obj-pbl-$(CONFIG_FS_FAT) += fat/ obj-y += fs.o libfs.o obj-$(CONFIG_FS_JFFS2) += jffs2/ obj-$(CONFIG_FS_UBIFS) += ubifs/ 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 99cbdb920c..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); @@ -333,11 +335,21 @@ static struct inode *cramfs_alloc_inode(struct super_block *sb) return &info->i_inode; } +static void cramfs_destroy_inode(struct inode *inode) +{ + struct cramfs_inode_info *info; + + info = to_cramfs_inode_info(inode); + + free(info); +} + 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; @@ -427,11 +439,12 @@ static const struct inode_operations cramfs_symlink_inode_operations = static const struct super_operations cramfs_ops = { .alloc_inode = cramfs_alloc_inode, + .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; @@ -475,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; @@ -483,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 5341e39e67..376c62be9e 100644 --- a/fs/devfs-core.c +++ b/fs/devfs-core.c @@ -3,9 +3,6 @@ * * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * - * See file CREDITS for list of people who contributed to this - * project. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. @@ -40,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); } @@ -52,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; @@ -65,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; } @@ -87,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; @@ -103,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; @@ -116,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; @@ -158,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; @@ -167,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; } @@ -180,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) @@ -222,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; @@ -237,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; @@ -256,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) { @@ -274,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); @@ -295,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) @@ -304,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); @@ -317,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; @@ -327,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; @@ -351,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); @@ -373,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, @@ -389,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; @@ -422,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[]) { @@ -484,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; @@ -497,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); @@ -532,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) { @@ -542,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) { @@ -580,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; @@ -593,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 e1893d1bd0..c8ddbbdab0 100644 --- a/fs/devfs.c +++ b/fs/devfs.c @@ -3,9 +3,6 @@ * * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * - * See file CREDITS for list of people who contributed to this - * project. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. @@ -31,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; @@ -57,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; @@ -84,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); @@ -147,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; @@ -163,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) @@ -203,13 +163,20 @@ static struct inode *devfs_alloc_inode(struct super_block *sb) return &node->inode; } +static void devfs_destroy_inode(struct inode *inode) +{ + struct devfs_inode *node = container_of(inode, struct devfs_inode, inode); + + free(node); +} + static int devfs_iterate(struct file *file, struct dir_context *ctx) { struct cdev *cdev; 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); } @@ -263,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; @@ -282,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); @@ -317,12 +288,13 @@ static const struct inode_operations devfs_dir_inode_operations = static const struct super_operations devfs_ops = { .alloc_inode = devfs_alloc_inode, + .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; @@ -334,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, @@ -3,9 +3,6 @@ * * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * - * See file CREDITS for list of people who contributed to this - * project. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. @@ -31,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; @@ -131,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); @@ -154,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); @@ -176,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); @@ -199,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; @@ -252,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; @@ -263,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; @@ -277,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; @@ -292,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; @@ -305,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; @@ -339,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; @@ -359,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; @@ -378,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); @@ -389,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; @@ -438,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)); @@ -475,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 9eadda4121..b199318061 100644 --- a/fs/efivarfs.c +++ b/fs/efivarfs.c @@ -3,9 +3,6 @@ * * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * - * See file CREDITS for list of people who contributed to this - * project. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. @@ -31,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 { @@ -50,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; @@ -172,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; @@ -203,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; @@ -248,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; @@ -258,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; @@ -267,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; @@ -288,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; @@ -307,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; @@ -318,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); @@ -336,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); @@ -345,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; @@ -370,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; @@ -409,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; @@ -422,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, @@ -446,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 82d4c581e0..df82b629cd 100644 --- a/fs/ext4/ext_barebox.c +++ b/fs/ext4/ext_barebox.c @@ -3,9 +3,6 @@ * * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * - * See file CREDITS for list of people who contributed to this - * project. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. @@ -30,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; } @@ -51,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); @@ -61,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; @@ -121,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); @@ -130,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; @@ -212,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; @@ -221,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: @@ -250,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; @@ -265,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; @@ -295,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 b1def851cf..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 @@ -8,9 +10,16 @@ if FS_FAT config FS_FAT_WRITE bool prompt "FAT write support" + help + Enable support for writing in FAT partitions. + Note: This doesn't apply to FAT usage in barebox PBL. + config FS_FAT_LFN - bool + def_bool y prompt "Support long filenames" + help + Enable support for file names other than 8.3. + Note: This doesn't apply to FAT usage in barebox PBL. endif diff --git a/fs/fat/Makefile b/fs/fat/Makefile index efc89ec67d..7a7a5ccdc6 100644 --- a/fs/fat/Makefile +++ b/fs/fat/Makefile @@ -1 +1,5 @@ -obj-y += ff.o fat.o +# 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 f0d29dc390..57626d2fbd 100644 --- a/fs/fat/diskio.h +++ b/fs/fat/diskio.h @@ -1,10 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + /*----------------------------------------------------------------------- / Low level disk interface modlue include file /-----------------------------------------------------------------------*/ #ifndef _DISKIO -#define _READONLY 0 /* 1: Remove write functions */ +#ifdef __PBL__ +#define _READONLY 1 /* 1: Remove write functions */ +#else +#define _READONLY 0 +#endif + #define _USE_IOCTL 1 /* 1: Use disk_ioctl fucntion */ #include "integer.h" diff --git a/fs/fat/fat-diskio.c b/fs/fat/fat-diskio.c new file mode 100644 index 0000000000..aa16d3bdc4 --- /dev/null +++ b/fs/fat/fat-diskio.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * fat.c - FAT filesystem barebox driver + * + * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + */ + +#include <common.h> +#include <linux/ctype.h> +#include "integer.h" +#include "ff.h" +#include "diskio.h" + +DSTATUS disk_status(FATFS *fat) +{ + return 0; +} + +DWORD get_fattime(void) +{ + return 0; +} + +DRESULT disk_ioctl (FATFS *fat, BYTE command, void *buf) +{ + return 0; +} + +WCHAR ff_convert(WCHAR src, UINT dir) +{ + if (src <= 0x80) + return src; + else + return '?'; +} + +WCHAR ff_wtoupper(WCHAR chr) +{ + if (chr <= 0x80) + return toupper(chr); + else + return '?'; +} diff --git a/fs/fat/fat-pbl.c b/fs/fat/fat-pbl.c new file mode 100644 index 0000000000..6b8a807657 --- /dev/null +++ b/fs/fat/fat-pbl.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * fat-pbl.c - PBL FAT filesystem barebox driver + * + * Copyright (c) 2019 Ahmad Fatoum, Pengutronix + */ + +#define pr_fmt(fmt) "fat-pbl: " fmt + +#include <common.h> +#include <pbl/bio.h> +#include "integer.h" +#include "ff.h" +#include "diskio.h" + +DRESULT disk_read(FATFS *fat, BYTE *buf, DWORD sector, BYTE count) +{ + int ret = pbl_bio_read(fat->userdata, sector, buf, count); + return ret != count ? ret : 0; +} + +ssize_t pbl_fat_load(struct pbl_bio *bio, const char *filename, void *dest, size_t len) +{ + FATFS fs = {}; + FIL file = {}; + UINT nread; + int ret; + + fs.userdata = bio; + + /* mount fs */ + ret = f_mount(&fs); + if (ret) { + pr_debug("f_mount(%s) failed: %d\n", filename, ret); + return ret; + } + + ret = f_open(&fs, &file, filename, FA_OPEN_EXISTING | FA_READ); + if (ret) { + pr_debug("f_open(%s) failed: %d\n", filename, ret); + return ret; + } + + pr_debug("Reading file %s to 0x%p\n", filename, dest); + + ret = f_read(&file, dest, len, &nread); + if (ret) { + pr_debug("f_read failed: %d\n", ret); + return ret; + } + + return f_size(&file) <= len ? nread : -ENOSPC; +} diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 394c75ffc4..f3c7f9b863 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -3,9 +3,6 @@ * * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * - * See file CREDITS for list of people who contributed to this - * project. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. @@ -68,41 +65,10 @@ DRESULT disk_write(FATFS *fat, const BYTE *buf, DWORD sector, BYTE count) return 0; } -DSTATUS disk_status(FATFS *fat) -{ - return 0; -} - -DWORD get_fattime(void) -{ - return 0; -} - -DRESULT disk_ioctl (FATFS *fat, BYTE command, void *buf) -{ - return 0; -} - -WCHAR ff_convert(WCHAR src, UINT dir) -{ - if (src <= 0x80) - return src; - else - return '?'; -} - -WCHAR ff_wtoupper(WCHAR chr) -{ - if (chr <= 0x80) - return toupper(chr); - else - return '?'; -} - /* ---------------------------------------------------------------*/ #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; @@ -117,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; @@ -131,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; @@ -145,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; @@ -159,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; @@ -177,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; @@ -201,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; @@ -230,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; @@ -238,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; @@ -252,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; @@ -268,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; @@ -280,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; @@ -305,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; @@ -335,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; @@ -345,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; @@ -368,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; @@ -396,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/ff.c b/fs/fat/ff.c index 4d30433e5f..c8d57ce500 100644 --- a/fs/fat/ff.c +++ b/fs/fat/ff.c @@ -96,6 +96,7 @@ #include <filetype.h> #include "ff.h" /* FatFs configurations and declarations */ #include "diskio.h" /* Declarations of low level disk I/O functions */ +#include <pbl.h> #if _FATFS != 8237 #error Wrong include file (ff.h). @@ -214,7 +215,7 @@ #define DDE 0xE5 /* Deleted directory enrty mark in DIR_Name[0] */ #define NDDE 0x05 /* Replacement of a character collides with DDE */ -#ifndef CONFIG_FS_FAT_LFN +#ifndef FS_FAT_LFN #define DEF_NAMEBUF BYTE sfn[12] #define INIT_BUF(dobj) (dobj).fn = sfn #define FREE_BUF() @@ -250,7 +251,7 @@ int move_window ( wsect = fs->winsect; if (wsect != sector) { /* Changed current window */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE if (fs->wflag) { /* Write back dirty window if needed */ if (disk_write(fs, fs->win, wsect, 1) != RES_OK) return -EIO; @@ -277,7 +278,7 @@ int move_window ( /* * Clean-up cached data */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE static int sync ( /* 0: successful, -EIO: failed */ FATFS *fs /* File system object */ @@ -372,7 +373,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster /* * FAT access - Change value of a FAT entry */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE static int put_fat ( FATFS *fs, /* File system object */ @@ -431,7 +432,7 @@ static int put_fat ( return res; } -#endif /* CONFIG_FS_FAT_WRITE */ +#endif /* FS_FAT_WRITE */ @@ -439,7 +440,7 @@ static int put_fat ( /* * FAT handling - Remove a cluster chain */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE static int remove_chain ( FATFS *fs, /* File system object */ @@ -506,7 +507,7 @@ int remove_chain ( /* * FAT handling - Stretch or Create a cluster chain */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ FATFS *fs, /* File system object */ @@ -566,7 +567,7 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err return ncl; /* Return new cluster number or error code */ } -#endif /* CONFIG_FS_FAT_WRITE */ +#endif /* FS_FAT_WRITE */ /* * Directory handling - Set directory index @@ -657,7 +658,7 @@ static int dir_next ( /* 0:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and return -EIO; if (clst >= dj->fs->n_fatent) { /* When it reached end of dynamic table */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE BYTE c; if (!stretch) @@ -708,7 +709,7 @@ static int dir_next ( /* 0:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and /* * LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */ -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN /* Offset of LFN chars in the directory entry */ static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; @@ -784,7 +785,7 @@ int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ } -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE static void fit_lfn ( const WCHAR *lfnbuf, /* Pointer to the LFN buffer */ @@ -824,7 +825,7 @@ void fit_lfn ( /* * Create numbered name */ -#if defined(CONFIG_FS_FAT_LFN) && defined(CONFIG_FS_FAT_WRITE) +#if defined(FS_FAT_LFN) && defined(FS_FAT_WRITE) static void gen_numname ( BYTE *dst, /* Pointer to generated SFN */ const BYTE *src, /* Pointer to source SFN to be modified */ @@ -874,7 +875,7 @@ static void gen_numname ( /* * Calculate sum of an SFN */ -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN static BYTE sum_sfn ( const BYTE *dir /* Ptr to directory entry */ ) @@ -897,7 +898,7 @@ static int dir_find ( { int res; BYTE c, *dir; -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN BYTE a, ord, sum; #endif @@ -905,7 +906,7 @@ static int dir_find ( if (res != 0) return res; -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN ord = sum = 0xFF; #endif do { @@ -919,7 +920,7 @@ static int dir_find ( res = -ENOENT; break; } -#ifdef CONFIG_FS_FAT_LFN /* LFN configuration */ +#ifdef FS_FAT_LFN /* LFN configuration */ a = dir[DIR_Attr] & AM_MASK; if (c == DDE || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ @@ -970,7 +971,7 @@ static int dir_read ( { int res; BYTE c, *dir; -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN BYTE a, ord = 0xFF, sum = 0xFF; #endif @@ -986,7 +987,7 @@ static int dir_read ( res = -ENOENT; break; } -#ifdef CONFIG_FS_FAT_LFN /* LFN configuration */ +#ifdef FS_FAT_LFN /* LFN configuration */ a = dir[DIR_Attr] & AM_MASK; if (c == DDE || c == '.' || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ ord = 0xFF; @@ -1025,7 +1026,7 @@ static int dir_read ( /* * Register an object to the directory */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE static int dir_register ( /* 0:Successful, FR_DENIED:No free entry or too many SFN collision, -EIO:Disk error */ FF_DIR *dj /* Target directory with object name to be created */ @@ -1033,7 +1034,7 @@ int dir_register ( /* 0:Successful, FR_DENIED:No free entry or too many SFN coll { int res; BYTE c, *dir; -#ifdef CONFIG_FS_FAT_LFN /* LFN configuration */ +#ifdef FS_FAT_LFN /* LFN configuration */ WORD n, ne, is; BYTE sn[12], *fn, sum; WCHAR *lfn; @@ -1127,7 +1128,7 @@ int dir_register ( /* 0:Successful, FR_DENIED:No free entry or too many SFN coll dir = dj->dir; memset(dir, 0, SZ_DIR); /* Clean the entry */ memcpy(dir, dj->fn, 11); /* Put SFN */ -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */ #endif dj->fs->wflag = 1; @@ -1136,18 +1137,18 @@ int dir_register ( /* 0:Successful, FR_DENIED:No free entry or too many SFN coll return res; } -#endif /* CONFIG_FS_FAT_WRITE */ +#endif /* FS_FAT_WRITE */ /* * Remove an object from the directory */ -#if defined CONFIG_FS_FAT_WRITE +#if defined FS_FAT_WRITE static int dir_remove ( /* 0: Successful, -EIO: A disk error */ FF_DIR *dj /* Directory object pointing the entry to be removed */ ) { int res; -#ifdef CONFIG_FS_FAT_LFN /* LFN configuration */ +#ifdef FS_FAT_LFN /* LFN configuration */ WORD i; i = dj->index; /* SFN index */ @@ -1181,7 +1182,7 @@ static int dir_remove ( /* 0: Successful, -EIO: A disk error */ return res; } -#endif /* CONFIG_FS_FAT_WRITE */ +#endif /* FS_FAT_WRITE */ /* * Pick a segment and create the object name in directory form @@ -1195,7 +1196,7 @@ static int create_name ( static const BYTE excvt[] = _EXCVT; /* Upper conversion table for extended chars */ #endif -#ifdef CONFIG_FS_FAT_LFN /* LFN configuration */ +#ifdef FS_FAT_LFN /* LFN configuration */ BYTE b, cf; WCHAR w, *lfn; UINT i, ni, si, di; @@ -1410,7 +1411,7 @@ static void get_fileinfo ( /* No return code */ break; if (c == NDDE) c = (TCHAR)DDE; -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN if ((nt & NS_BODY) && isupper(c)) c += 0x20; #endif @@ -1428,7 +1429,7 @@ static void get_fileinfo ( /* No return code */ c = dir[i]; if (c == ' ') break; -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN if ((nt & NS_EXT) && isupper(c)) c += 0x20; #endif @@ -1449,7 +1450,7 @@ static void get_fileinfo ( /* No return code */ } *p = 0; /* Terminate SFN str by a \0 */ -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN if (fno->lfname && fno->lfsize) { TCHAR *tp = fno->lfname; WCHAR w, *lfn; @@ -1668,7 +1669,7 @@ static int chk_mounted ( /* 0(0): successful, !=0: any error occurred */ if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return -EINVAL; -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE /* Initialize cluster allocation information */ fs->free_clust = 0xFFFFFFFF; fs->last_clust = 0; @@ -1723,7 +1724,7 @@ int f_open ( fp->fs = NULL; /* Clear file object */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; dj.fs = fatfs; #else @@ -1735,7 +1736,7 @@ int f_open ( res = follow_path(&dj, path); /* Follow the file path */ dir = dj.dir; -#ifdef CONFIG_FS_FAT_WRITE /* R/W configuration */ +#ifdef FS_FAT_WRITE /* R/W configuration */ if (res == 0) { if (!dir) /* Current dir itself */ res = -EISDIR; @@ -1870,7 +1871,7 @@ int f_read ( cc = fp->fs->csize - csect; if (disk_read(fp->fs, rbuff, sect, (BYTE)cc) != RES_OK) ABORT(fp->fs, -EIO); -#if defined CONFIG_FS_FAT_WRITE +#if defined FS_FAT_WRITE /* Replace one of the read sectors with cached data if it contains a dirty sector */ if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) memcpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs)); @@ -1879,7 +1880,7 @@ int f_read ( continue; } if (fp->dsect != sect) { /* Load data sector if not in cache */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fp->fs, fp->buf, fp->dsect, 1) != RES_OK) ABORT(fp->fs, -EIO); @@ -1903,7 +1904,7 @@ int f_read ( -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE /* * Write File */ @@ -2044,7 +2045,7 @@ int f_sync ( return res; } -#endif /* CONFIG_FS_FAT_WRITE */ +#endif /* FS_FAT_WRITE */ /* * Close File @@ -2053,7 +2054,7 @@ int f_close ( FIL *fp /* Pointer to the file object to be closed */ ) { -#ifndef CONFIG_FS_FAT_WRITE +#ifndef FS_FAT_WRITE fp->fs = 0; /* Discard file object */ return 0; #else @@ -2082,7 +2083,7 @@ int f_lseek ( return -ERESTARTSYS; if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE && !(fp->flag & FA_WRITE) #endif ) ofs = fp->fsize; @@ -2098,7 +2099,7 @@ int f_lseek ( clst = fp->clust; } else { /* When seek to back cluster, */ clst = fp->sclust; /* start from the first cluster */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE if (clst == 0) { /* If no cluster chain, create a new chain */ clst = create_chain(fp->fs, 0); if (clst == 1) @@ -2112,7 +2113,7 @@ int f_lseek ( } if (clst != 0) { while (ofs > bcs) { /* Cluster following loop */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ /* Force stretch if in write mode */ clst = create_chain(fp->fs, clst); @@ -2143,7 +2144,7 @@ int f_lseek ( } } if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fp->fs, fp->buf, fp->dsect, 1) != RES_OK) ABORT(fp->fs, -EIO); @@ -2154,7 +2155,7 @@ int f_lseek ( ABORT(fp->fs, -EIO); fp->dsect = nsect; } -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */ fp->fsize = fp->fptr; fp->flag |= FA__WRITTEN; @@ -2269,7 +2270,7 @@ int f_stat ( return res; } -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE /* * Get Number of Free Clusters */ @@ -2706,4 +2707,4 @@ out: return res; } -#endif /* CONFIG_FS_FAT_WRITE */ +#endif /* FS_FAT_WRITE */ diff --git a/fs/fat/ff.h b/fs/fat/ff.h index e86ca3aae0..c961de46e1 100644 --- a/fs/fat/ff.h +++ b/fs/fat/ff.h @@ -17,6 +17,18 @@ #ifndef _FATFS #define _FATFS 8237 /* Revision ID */ +#ifndef __PBL__ + +#ifdef CONFIG_FS_FAT_LFN +#define FS_FAT_LFN 1 +#endif + +#ifdef CONFIG_FS_FAT_WRITE +#define FS_FAT_WRITE 1 +#endif + +#endif + #include <asm/unaligned.h> #include <linux/list.h> @@ -30,7 +42,7 @@ /* Type of path name strings on FatFs API */ #if _LFN_UNICODE /* Unicode string */ -#ifndef CONFIG_FS_FAT_LFN +#ifndef FS_FAT_LFN #error _LFN_UNICODE must be 0 in non-LFN cfg. #endif #ifndef _INC_TCHAR @@ -63,7 +75,7 @@ typedef struct { #if _MAX_SS != 512 WORD ssize; /* Bytes per sector (512,1024,2048,4096) */ #endif -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE DWORD last_clust; /* Last allocated cluster */ DWORD free_clust; /* Number of free clusters */ DWORD fsi_sector; /* fsinfo sector (FAT32) */ @@ -92,7 +104,7 @@ typedef struct { DWORD sclust; /* File start cluster (0 when fsize==0) */ DWORD clust; /* Current cluster */ DWORD dsect; /* Current data sector */ -#ifdef CONFIG_FS_FAT_WRITE +#ifdef FS_FAT_WRITE DWORD dir_sect; /* Sector containing the directory entry */ BYTE* dir_ptr; /* Ponter to the directory entry in the window */ #endif @@ -119,7 +131,7 @@ typedef struct { DWORD sect; /* Current sector */ BYTE* dir; /* Pointer to the current SFN entry in the win[] */ BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN WCHAR* lfn; /* Pointer to the LFN working buffer */ WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ #endif @@ -135,7 +147,7 @@ typedef struct { WORD ftime; /* Last modified time */ BYTE fattrib; /* Attribute */ TCHAR fname[13]; /* Short file name (8.3 format) */ -#ifdef CONFIG_FS_FAT_LFN +#ifdef FS_FAT_LFN TCHAR* lfname; /* Pointer to the LFN buffer */ UINT lfsize; /* Size of LFN buffer in TCHAR */ #endif 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 */ /*-------------------------------------------*/ @@ -3,9 +3,6 @@ * * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * - * See file CREDITS for list of people who contributed to this - * project. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. @@ -34,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> @@ -69,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; @@ -77,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); @@ -89,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); @@ -113,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) { @@ -131,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; } @@ -171,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]; } @@ -196,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)) @@ -214,23 +371,20 @@ 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; return 0; } 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)) @@ -242,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) { @@ -259,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; @@ -267,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)) @@ -292,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)) @@ -308,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; @@ -332,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)) @@ -357,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)) @@ -373,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)) @@ -386,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; @@ -404,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) { @@ -436,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; } @@ -445,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)) @@ -459,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)) @@ -485,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)) @@ -511,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) @@ -539,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; @@ -549,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); @@ -649,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); @@ -666,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 = { @@ -697,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) { @@ -734,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; } @@ -759,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; } /** @@ -774,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) { @@ -819,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; @@ -841,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; @@ -851,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; @@ -870,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) @@ -883,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) { @@ -894,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); @@ -920,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)) @@ -934,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); @@ -958,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); @@ -982,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; @@ -1089,10 +1337,15 @@ void iget_failed(struct inode *inode) void iput(struct inode *inode) { - if (!inode->i_count) + if (!inode) return; inode->i_count--; + + if (!inode->i_count) { + list_del(&inode->i_sb_list); + destroy_inode(inode); + } } struct inode *iget(struct inode *inode) @@ -1258,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) @@ -1267,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; @@ -1367,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 { @@ -1390,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) @@ -1420,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; @@ -1460,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); @@ -1588,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; @@ -1639,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; } @@ -1727,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; } @@ -1736,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; /* @@ -1755,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)); @@ -1784,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; @@ -1810,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) @@ -1846,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) @@ -1937,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; @@ -1948,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; @@ -1992,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)) @@ -2011,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) { @@ -2021,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; @@ -2035,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); @@ -2044,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); @@ -2064,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; @@ -2095,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); - s = path_init(&nd, flags); + set_nameidata(&nd, name); + + 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); @@ -2129,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; @@ -2187,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; @@ -2205,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; @@ -2221,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); @@ -2260,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; @@ -2278,9 +2531,46 @@ int open(const char *pathname, int flags, ...) struct dentry *dentry = NULL; struct nameidata nd; const char *s; + struct filename *filename; + + 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); - set_nameidata(&nd, AT_FDCWD, getname(pathname)); - s = path_init(&nd, LOOKUP_FOLLOW); + s = path_init(dirfd, &nd, LOOKUP_FOLLOW); + if (IS_ERR(s)) + return PTR_ERR(s); while (1) { error = link_path_walk(s, &nd); @@ -2330,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; @@ -2345,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); @@ -2367,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) @@ -2382,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; @@ -2423,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) { @@ -2452,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) @@ -2503,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; @@ -2552,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; @@ -2582,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; @@ -2615,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) { @@ -2643,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) { @@ -2687,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 @@ -2694,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; } @@ -2742,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. @@ -2757,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 = {}; @@ -2787,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); @@ -2833,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); @@ -2855,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; @@ -2886,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); @@ -2894,10 +3322,8 @@ int umount(const char *pathname) } } - if (!fsdev) { - errno = EFAULT; - return -EFAULT; - } + if (!fsdev) + return errno_set(-EFAULT); return fsdev_umount(fsdev); } @@ -3023,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; @@ -3053,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[]) { @@ -3072,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); @@ -3093,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) { @@ -3147,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; @@ -8,9 +8,6 @@ * Based on U-Boot NFS code which is based on NetBSD code with * major changes to support nfs3. * - * See file CREDITS for list of people who contributed to this - * project. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. @@ -29,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> @@ -122,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; @@ -131,6 +127,7 @@ struct nfs_fh { }; struct packet { + struct list_head list; int len; char data[]; }; @@ -145,7 +142,7 @@ struct nfs_priv { unsigned manual_nfs_port:1; uint32_t rpc_id; struct nfs_fh rootfh; - struct packet *nfs_packet; + struct list_head packets; }; struct file_priv { @@ -175,10 +172,6 @@ static void nfs_set_fh(struct inode *inode, struct nfs_fh *fh) static uint64_t nfs_timer_start; -static int nfs_state; -#define STATE_DONE 1 -#define STATE_START 2 - /* * common types used in more than one request: * @@ -269,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; @@ -366,18 +427,10 @@ static int rpc_check_reply(struct packet *pkt, int rpc_prog, *nfserr = 0; - if (!pkt) - return -EAGAIN; - memcpy(&rpc, pkt->data, sizeof(rpc)); - if (ntoh32(rpc.id) != rpc_id) { - if (rpc_id - ntoh32(rpc.id) == 1) - /* stale packet, wait a bit longer */ - return 0; - - return -EINVAL; - } + if (ntoh32(rpc.id) != rpc_id) + return -EAGAIN; if (rpc.rstatus || rpc.verifier || @@ -392,11 +445,17 @@ static int rpc_check_reply(struct packet *pkt, int rpc_prog, *nfserr = ntoh32(net_read_uint32(data)); *nfserr = -*nfserr; - debug("%s: state: %d, err %d\n", __func__, nfs_state, *nfserr); + debug("%s: err %d\n", __func__, *nfserr); return 0; } +static void nfs_free_packet(struct packet *packet) +{ + list_del(&packet->list); + free(packet); +} + /* * rpc_req - synchronous RPC request */ @@ -409,6 +468,7 @@ static struct packet *rpc_req(struct nfs_priv *npriv, int rpc_prog, unsigned char *payload = net_udp_get_payload(npriv->con); int nfserr; int tries = 0; + struct packet *packet; npriv->rpc_id++; @@ -453,12 +513,7 @@ again: nfs_timer_start = get_time_ns(); - nfs_state = STATE_START; - - while (nfs_state != STATE_DONE) { - if (ctrlc()) - return ERR_PTR(-EINTR); - + while (1) { net_poll(); if (is_timeout(nfs_timer_start, NFS_TIMEOUT)) { @@ -468,19 +523,28 @@ again: goto again; } - ret = rpc_check_reply(npriv->nfs_packet, rpc_prog, + if (list_empty(&npriv->packets)) + continue; + + packet = list_first_entry(&npriv->packets, struct packet, list); + + ret = rpc_check_reply(packet, rpc_prog, npriv->rpc_id, &nfserr); - if (!ret) { + if (ret == -EAGAIN) { + nfs_free_packet(packet); + continue; + } else if (ret) { + nfs_free_packet(packet); + return ERR_PTR(ret); + } else { if (rpc_prog == PROG_NFS && nfserr) { - free(npriv->nfs_packet); + nfs_free_packet(packet); return ERR_PTR(nfserr); } else { - return npriv->nfs_packet; + return packet; } } } - - return npriv->nfs_packet; } /* @@ -505,7 +569,13 @@ static int rpc_lookup_req(struct nfs_priv *npriv, uint32_t prog, uint32_t ver) port = ntoh32(net_read_uint32(nfs_packet->data + sizeof(struct rpc_reply))); - free(nfs_packet); + 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; } @@ -645,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; @@ -670,18 +740,29 @@ 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) { printf("%s: file handle too big: %lu\n", __func__, (unsigned long)npriv->rootfh.size); - free(nfs_packet); + nfs_free_packet(nfs_packet); return -EIO; } memcpy(npriv->rootfh.data, p, npriv->rootfh.size); - free(nfs_packet); + nfs_free_packet(nfs_packet); return 0; } @@ -709,7 +790,7 @@ static void nfs_umount_req(struct nfs_priv *npriv) nfs_packet = rpc_req(npriv, PROG_MOUNT, MOUNT_UMOUNT, data, len); if (!IS_ERR(nfs_packet)) - free(nfs_packet); + nfs_free_packet(nfs_packet); } /* @@ -722,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; @@ -764,10 +845,17 @@ 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) { + nfs_free_packet(nfs_packet); debug("%s: file handle too big: %u\n", __func__, ninode->fh.size); return -EIO; @@ -777,7 +865,7 @@ static int nfs_lookup_req(struct nfs_priv *npriv, struct nfs_fh *fh, nfs_read_post_op_attr(p, inode); - free(nfs_packet); + nfs_free_packet(nfs_packet); return 0; } @@ -789,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; @@ -847,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 */ @@ -857,7 +951,7 @@ static void *nfs_readdirattr_req(struct nfs_priv *npriv, struct nfs_dir *dir) len = (void *)nfs_packet->data + nfs_packet->len - (void *)p; if (!len) { printf("%s: huh, no payload left\n", __func__); - free(nfs_packet); + nfs_free_packet(nfs_packet); return NULL; } @@ -865,7 +959,7 @@ static void *nfs_readdirattr_req(struct nfs_priv *npriv, struct nfs_dir *dir) memcpy(buf, p, len); - free(nfs_packet); + nfs_free_packet(nfs_packet); xdr_init(&dir->stream, buf, len); @@ -881,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; @@ -924,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); @@ -942,30 +1041,31 @@ static int nfs_read_req(struct file_priv *priv, uint64_t offset, p += 2; if (readlen && !rlen && !eof) { - free(nfs_packet); + nfs_free_packet(nfs_packet); return -EIO; } kfifo_put(priv->fifo, (char *)p, rlen); - free(nfs_packet); + nfs_free_packet(nfs_packet); return 0; } -static void nfs_handler(void *ctx, char *packet, unsigned len) +static void nfs_handler(void *ctx, char *p, unsigned len) { - char *pkt = net_eth_to_udp_payload(packet); + char *pkt = net_eth_to_udp_payload(p); struct nfs_priv *npriv = ctx; + struct packet *packet; - nfs_state = STATE_DONE; + packet = xmalloc(sizeof(*packet) + len); + memcpy(packet->data, pkt, len); + packet->len = len; - npriv->nfs_packet = xmalloc(sizeof(*npriv->nfs_packet) + len); - memcpy(npriv->nfs_packet->data, pkt, len); - npriv->nfs_packet->len = 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; } @@ -982,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; @@ -1018,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++; @@ -1032,7 +1138,7 @@ static int nfs_readlink_req(struct nfs_priv *npriv, struct nfs_fh *fh, *target = xzalloc(len + 1); memcpy(*target, p, len); - free(nfs_packet); + nfs_free_packet(nfs_packet); return 0; } @@ -1050,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); @@ -1072,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; @@ -1081,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; @@ -1103,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; @@ -1203,6 +1309,13 @@ static struct inode *nfs_alloc_inode(struct super_block *sb) return &node->inode; } +static void nfs_destroy_inode(struct inode *inode) +{ + struct nfs_inode *node = nfsi(inode); + + free(node); +} + static const struct inode_operations nfs_file_inode_operations; static const struct file_operations nfs_dir_operations; static const struct inode_operations nfs_dir_inode_operations; @@ -1274,11 +1387,12 @@ static const struct inode_operations nfs_dir_inode_operations = static const struct super_operations nfs_ops = { .alloc_inode = nfs_alloc_inode, + .destroy_inode = nfs_destroy_inode, }; 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; @@ -1311,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); @@ -1323,6 +1437,8 @@ static int nfs_probe(struct device_d *dev) dev->priv = npriv; + INIT_LIST_HEAD(&npriv->packets); + debug("nfs: mount: %s\n", fsdev->backingstore); path = strchr(tmp, ':'); @@ -1389,6 +1505,7 @@ static int nfs_probe(struct device_d *dev) free(tmp); sb->s_op = &nfs_ops; + sb->s_d_op = &no_revalidate_d_ops; inode = new_inode(sb); nfs_set_fh(inode, &npriv->rootfh); @@ -1408,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; @@ -1419,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 7e7dc7aca9..117e69b70c 100644 --- a/fs/ramfs.c +++ b/fs/ramfs.c @@ -3,9 +3,6 @@ * * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * - * See file CREDITS for list of people who contributed to this - * project. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. @@ -26,29 +23,31 @@ #include <errno.h> #include <linux/stat.h> #include <xfuncs.h> +#include <linux/sizes.h> #define CHUNK_SIZE (4096 * 2) struct ramfs_chunk { char *data; - struct ramfs_chunk *next; + unsigned long ofs; + int size; + struct list_head list; }; struct ramfs_inode { struct inode inode; char *name; - struct ramfs_inode *parent; - struct ramfs_inode *next; - struct ramfs_inode *child; char *symlink; ulong mode; - ulong size; - struct ramfs_chunk *data; + /* bytes used in this inode */ + unsigned long size; + /* bytes currently allocated for this inode */ + unsigned long alloc_size; + + struct list_head data; - /* Points to recently used chunk */ - int recent_chunk; - struct ramfs_chunk *recent_chunkp; + struct ramfs_chunk *current_chunk; }; static inline struct ramfs_inode *to_ramfs_inode(struct inode *inode) @@ -56,10 +55,6 @@ static inline struct ramfs_inode *to_ramfs_inode(struct inode *inode) return container_of(inode, struct ramfs_inode, inode); } -struct ramfs_priv { - struct ramfs_inode root; -}; - /* ---------------------------------------------------------------*/ static const struct super_operations ramfs_ops; @@ -99,18 +94,25 @@ static struct inode *ramfs_get_inode(struct super_block *sb, const struct inode return inode; } -static struct ramfs_chunk *ramfs_get_chunk(void) +#define MIN_SIZE SZ_8K + +static struct ramfs_chunk *ramfs_get_chunk(unsigned long size) { struct ramfs_chunk *data = malloc(sizeof(struct ramfs_chunk)); + if (!data) return NULL; - data->data = calloc(CHUNK_SIZE, 1); + if (size < MIN_SIZE) + size = MIN_SIZE; + + data->data = calloc(size, 1); if (!data->data) { free(data); return NULL; } - data->next = NULL; + + data->size = size; return data; } @@ -170,23 +172,6 @@ static int ramfs_symlink(struct inode *dir, struct dentry *dentry, static int ramfs_unlink(struct inode *dir, struct dentry *dentry) { - struct inode *inode = d_inode(dentry); - - if (inode) { - struct ramfs_inode *node = to_ramfs_inode(inode); - struct ramfs_chunk *chunk = node->data; - - node->data = NULL; - - while (chunk) { - struct ramfs_chunk *tmp = chunk; - - chunk = chunk->next; - - ramfs_put_chunk(tmp); - } - } - return simple_unlink(dir, dentry); } @@ -210,183 +195,215 @@ static const struct inode_operations ramfs_dir_inode_operations = .create = ramfs_create, }; -static struct ramfs_chunk *ramfs_find_chunk(struct ramfs_inode *node, int chunk) +static struct ramfs_chunk *ramfs_find_chunk(struct ramfs_inode *node, + unsigned long pos, int *ofs, int *len) { - struct ramfs_chunk *data; - int left = chunk; + struct ramfs_chunk *data, *cur = node->current_chunk; - if (chunk == 0) - return node->data; + if (cur && pos >= cur->ofs) + data = cur; + else + data = list_first_entry(&node->data, struct ramfs_chunk, list); - if (node->recent_chunk == chunk) - return node->recent_chunkp; + list_for_each_entry_from(data, &node->data, list) { + if (data->ofs + data->size > pos) { + *ofs = pos - data->ofs; + *len = data->ofs + data->size - pos; - if (node->recent_chunk < chunk && node->recent_chunk != 0) { - /* Start at last known chunk */ - data = node->recent_chunkp; - left -= node->recent_chunk; - } else { - /* Start at first chunk */ - data = node->data; - } + node->current_chunk = data; - while (left--) - data = data->next; + return data; + } + } - node->recent_chunkp = data; - node->recent_chunk = chunk; + pr_err("%s: no chunk for pos %ld found\n", __func__, pos); - return data; + 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); - int chunk; struct ramfs_chunk *data; - int ofs; - int now; - int pos = f->pos; + int ofs, len, now; + unsigned long pos = f->pos; int size = insize; - chunk = pos / CHUNK_SIZE; - debug("%s: reading from chunk %d\n", __FUNCTION__, chunk); + debug("%s: %p %zu @ %lld\n", __func__, node, insize, f->pos); - /* Position ourself in stream */ - data = ramfs_find_chunk(node, chunk); - ofs = pos % CHUNK_SIZE; + while (size) { + data = ramfs_find_chunk(node, pos, &ofs, &len); + if (!data) + return -EINVAL; + + debug("%s: pos: %lu ofs: %d len: %d\n", __func__, pos, ofs, len); + + now = min(size, len); - /* Read till end of current chunk */ - if (ofs) { - now = min(size, CHUNK_SIZE - ofs); - debug("Reading till end of node. size: %d\n", size); memcpy(buf, data->data + ofs, now); + size -= now; - pos += now; buf += now; - if (pos > node->size) - node->size = now; - data = data->next; - } - - /* Do full chunks */ - while (size >= CHUNK_SIZE) { - debug("do full chunk. size: %d\n", size); - memcpy(buf, data->data, CHUNK_SIZE); - data = data->next; - size -= CHUNK_SIZE; - pos += CHUNK_SIZE; - buf += CHUNK_SIZE; - } - - /* And the rest */ - if (size) { - debug("do rest. size: %d\n", size); - memcpy(buf, data->data, size); + pos += now; } 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); - int chunk; struct ramfs_chunk *data; - int ofs; - int now; - int pos = f->pos; + int ofs, len, now; + unsigned long pos = f->pos; int size = insize; - chunk = f->pos / CHUNK_SIZE; - debug("%s: writing to chunk %d\n", __FUNCTION__, chunk); + debug("%s: %p %zu @ %lld\n", __func__, node, insize, f->pos); - /* Position ourself in stream */ - data = ramfs_find_chunk(node, chunk); - ofs = f->pos % CHUNK_SIZE; + while (size) { + data = ramfs_find_chunk(node, pos, &ofs, &len); + if (!data) + return -EINVAL; + + debug("%s: pos: %lu ofs: %d len: %d\n", __func__, pos, ofs, len); + + now = min(size, len); - /* Write till end of current chunk */ - if (ofs) { - now = min(size, CHUNK_SIZE - ofs); - debug("writing till end of node. size: %d\n", size); memcpy(data->data + ofs, buf, now); + size -= now; - pos += now; buf += now; - if (pos > node->size) - node->size = now; - data = data->next; + pos += now; + } + + return insize; +} + +static void ramfs_truncate_down(struct ramfs_inode *node, unsigned long size) +{ + struct ramfs_chunk *data, *tmp; + + list_for_each_entry_safe(data, tmp, &node->data, list) { + if (data->ofs >= size) { + list_del(&data->list); + node->alloc_size -= data->size; + ramfs_put_chunk(data); + } } - /* Do full chunks */ - while (size >= CHUNK_SIZE) { - debug("do full chunk. size: %d\n", size); - memcpy(data->data, buf, CHUNK_SIZE); - data = data->next; - size -= CHUNK_SIZE; - pos += CHUNK_SIZE; - buf += CHUNK_SIZE; + node->current_chunk = NULL; +} + +static int ramfs_truncate_up(struct ramfs_inode *node, unsigned long size) +{ + struct ramfs_chunk *data, *tmp; + LIST_HEAD(list); + unsigned long add = size - node->alloc_size; + unsigned long chunksize = add; + unsigned long alloc_size = 0; + + if (node->alloc_size >= size) + return 0; + + /* + * We first try to allocate all space we need in a single chunk. + * This may fail because of fragmented memory, so in case we cannot + * allocate memory we successively decrease the chunk size until + * we have enough allocations made. + */ + while (1) { + unsigned long now = min(chunksize, add); + + data = ramfs_get_chunk(now); + if (!data) { + /* No luck, try with smaller chunk size */ + chunksize >>= 1; + + /* If we do not have even 128KiB then go out */ + if (chunksize < SZ_128K) + goto out; + + continue; + } + + data->ofs = node->alloc_size + alloc_size; + + alloc_size += data->size; + + list_add_tail(&data->list, &list); + + if (add <= data->size) + break; + + add -= data->size; } - /* And the rest */ - if (size) { - debug("do rest. size: %d\n", size); - memcpy(data->data, buf, size); + list_splice_tail(&list, &node->data); + + node->alloc_size += alloc_size; + + return 0; + +out: + list_for_each_entry_safe(data, tmp, &list, list) { + list_del(&data->list); + ramfs_put_chunk(data); } - return insize; + 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); - int oldchunks, newchunks; - struct ramfs_chunk *data = node->data; - - newchunks = (size + CHUNK_SIZE - 1) / CHUNK_SIZE; - oldchunks = (node->size + CHUNK_SIZE - 1) / CHUNK_SIZE; - - if (newchunks < oldchunks) { - if (!newchunks) - node->data = NULL; - while (newchunks--) - data = data->next; - while (data) { - struct ramfs_chunk *tmp; - tmp = data->next; - ramfs_put_chunk(data); - data = tmp; - } - if (node->recent_chunk > newchunks) - node->recent_chunk = 0; - } + int ret; - if (newchunks > oldchunks) { - if (data) { - data = ramfs_find_chunk(node, oldchunks - 1); - } else { - node->data = ramfs_get_chunk(); - if (!node->data) - return -ENOMEM; - data = node->data; - oldchunks = 1; - } + /* + * This is a malloc based filesystem, no need to support more + * memory than fits into unsigned long. + */ + if (size > ULONG_MAX) + return -ENOSPC; - while (data->next) - data = data->next; + debug("%s: %p cur: %ld new: %lld alloc: %ld\n", __func__, node, + node->size, size, node->alloc_size); - while (newchunks > oldchunks) { - data->next = ramfs_get_chunk(); - if (!data->next) - return -ENOMEM; - data = data->next; - oldchunks++; - } + if (size == node->size) + return 0; + + if (size < node->size) { + ramfs_truncate_down(node, size); + } else { + ret = ramfs_truncate_up(node, size); + if (ret) + return ret; } + node->size = size; + + return 0; +} + +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); + struct ramfs_chunk *data; + + if (list_empty(&node->data)) + return -EINVAL; + + if (!list_is_singular(&node->data)) + return -EINVAL; + + data = list_first_entry(&node->data, struct ramfs_chunk, list); + + *map = data->data; + return 0; } @@ -396,26 +413,31 @@ static struct inode *ramfs_alloc_inode(struct super_block *sb) node = xzalloc(sizeof(*node)); + INIT_LIST_HEAD(&node->data); + return &node->inode; } +static void ramfs_destroy_inode(struct inode *inode) +{ + struct ramfs_inode *node = to_ramfs_inode(inode); + + ramfs_truncate_down(node, 0); + + free(node); +} + static const struct super_operations ramfs_ops = { .alloc_inode = ramfs_alloc_inode, + .destroy_inode = ramfs_destroy_inode, }; -static int ramfs_probe(struct device_d *dev) +static int ramfs_probe(struct device *dev) { struct inode *inode; - struct ramfs_priv *priv = xzalloc(sizeof(struct ramfs_priv)); - 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; - dev->priv = priv; - - priv->root.name = "/"; - priv->root.mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; - priv->root.parent = &priv->root; - sb->s_op = &ramfs_ops; inode = ramfs_get_inode(sb, NULL, S_IFDIR); @@ -424,14 +446,14 @@ 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, .truncate = ramfs_truncate, .flags = FS_DRIVER_NO_DEV, .drv = { 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 38aff6d5b8..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 = {}; @@ -76,13 +78,21 @@ static struct inode *squashfs_alloc_inode(struct super_block *sb) return &node->vfs_inode; } +static void squashfs_destroy_inode(struct inode *inode) +{ + struct squashfs_inode_info *node = squashfs_i(inode); + + free(node); +} + static const struct super_operations squashfs_super_ops = { - .alloc_inode = squashfs_alloc_inode, + .alloc_inode = squashfs_alloc_inode, + .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; @@ -93,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) { @@ -102,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: @@ -111,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); @@ -122,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; @@ -156,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; @@ -188,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; @@ -242,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 */ @@ -3,9 +3,6 @@ * * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * - * See file CREDITS for list of people who contributed to this - * project. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. @@ -29,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 */ @@ -61,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; @@ -85,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) @@ -115,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]); @@ -122,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) @@ -134,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; @@ -200,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; } @@ -215,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; @@ -232,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) @@ -247,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) @@ -273,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: @@ -372,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)); @@ -400,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); @@ -492,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); @@ -500,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; @@ -543,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); @@ -556,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; @@ -663,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; @@ -698,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; @@ -727,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, @@ -751,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, |