diff options
Diffstat (limited to 'fs/fs.c')
-rw-r--r-- | fs/fs.c | 892 |
1 files changed, 580 insertions, 312 deletions
@@ -67,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; @@ -75,7 +219,7 @@ static FILE *files; static struct dentry *d_root; static struct vfsmount *mnt_root; -static struct fs_driver_d *ramfs_driver; +static struct fs_driver *ramfs_driver; static int init_fs(void) { @@ -91,8 +235,7 @@ postcore_initcall(init_fs); struct filename; -static struct fs_device_d *get_fsdevice_by_path(const char *path); -static int filename_lookup(struct filename *name, unsigned flags, +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); @@ -119,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) { @@ -137,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; } @@ -177,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]; } @@ -202,22 +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); -} -EXPORT_SYMBOL(creat); - -static int fsdev_truncate(struct device_d *dev, FILE *f, loff_t length) -{ - struct fs_driver_d *fsdrv = f->fsdev->driver; + struct fs_driver *fsdrv = f->fsdev->driver; return fsdrv->truncate ? fsdrv->truncate(dev, f, length) : -EROFS; } int ftruncate(int fd, loff_t length) { - FILE *f = fd_to_file(fd); + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -227,10 +372,8 @@ int ftruncate(int fd, loff_t length) return 0; ret = fsdev_truncate(&f->fsdev->dev, f, length); - if (ret) { - errno = -ret; - return ret; - } + if (ret) + return errno_set(ret); f->size = length; f->f_inode->i_size = f->size; @@ -240,8 +383,8 @@ int ftruncate(int fd, loff_t length) int ioctl(int fd, int request, void *buf) { - struct fs_driver_d *fsdrv; - FILE *f = fd_to_file(fd); + struct fs_driver *fsdrv; + FILE *f = fd_to_file(fd, false); int ret; if (IS_ERR(f)) @@ -253,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) { @@ -281,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)) @@ -306,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)) @@ -322,7 +462,7 @@ 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; fsdrv = f->fsdev->driver; @@ -338,6 +478,8 @@ static ssize_t __write(FILE *f, const void *buf, size_t count) if (f->size != FILE_SIZE_STREAM && f->pos + count > f->size) { 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; @@ -350,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)) @@ -375,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)) @@ -391,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)) @@ -404,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; @@ -457,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; } @@ -466,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)) @@ -489,17 +625,14 @@ int erase(int fd, loff_t count, loff_t 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)) @@ -519,17 +652,14 @@ int protect(int fd, size_t count, loff_t offset, int 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)) @@ -549,10 +679,7 @@ int discard_range(int fd, loff_t count, loff_t offset) else ret = -ENOSYS; - if (ret) - errno = -ret; - - return ret; + return errno_set(ret); } int protect_file(const char *file, int prot) @@ -572,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; @@ -590,49 +717,47 @@ void *memmap(int fd, int 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 != ramfs_driver) - assert_command_context(); + fsdrv = f->fsdev->driver; - if (fsdrv->close) - ret = fsdrv->close(&f->fsdev->dev, f); + if (fsdrv != ramfs_driver) + assert_command_context(); - put_file(f); + if (fsdrv->close) + ret = fsdrv->close(&f->fsdev->dev, f); + } - if (ret) - errno = -ret; + put_file(f); - return ret; + 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); @@ -688,9 +813,9 @@ 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; @@ -710,7 +835,7 @@ static void fs_remove(struct device_d *dev) if (fsdev->loop && fsdev->cdev) { cdev_remove_loop(fsdev->cdev); - ret = filename_lookup(getname(fsdev->backingstore), + ret = filename_lookup(AT_FDCWD, getname(fsdev->backingstore), LOOKUP_FOLLOW, &path); if (!ret) { mntput(path.mnt); @@ -744,7 +869,7 @@ 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); @@ -756,22 +881,31 @@ int register_fs_driver(struct fs_driver_d *fsdrv) } 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) { @@ -784,7 +918,7 @@ 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 = {}; @@ -793,7 +927,7 @@ int fsdev_open_cdev(struct fs_device_d *fsdev) parseopt_b(fsdev->options, "loop", &fsdev->loop); parseopt_llu_suffix(fsdev->options, "offset", &offset); if (fsdev->loop) { - ret = filename_lookup(getname(fsdev->backingstore), + ret = filename_lookup(AT_FDCWD, getname(fsdev->backingstore), LOOKUP_FOLLOW, &path); if (ret) return ret; @@ -822,7 +956,7 @@ 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; @@ -845,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) { @@ -890,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; @@ -921,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; @@ -940,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) @@ -1000,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)) @@ -1014,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); @@ -1038,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); @@ -1062,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; @@ -1343,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) @@ -1352,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; @@ -1452,21 +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; + struct dentry *d_root; }; struct filename { @@ -1476,9 +1638,11 @@ struct filename { static void set_nameidata(struct nameidata *p, struct filename *name) { + p->last = slash_name; p->stack = p->internal; p->name = name; p->total_link_count = 0; + p->d_root = d_root; } static void path_get(const struct path *path) @@ -1503,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; @@ -1543,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); @@ -1671,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; @@ -1722,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; } @@ -1810,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; } @@ -1819,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; /* @@ -1838,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)); @@ -1896,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) @@ -2025,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; @@ -2036,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 { + } 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; @@ -2080,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)) @@ -2099,7 +2272,8 @@ static int path_parentat(struct nameidata *nd, unsigned flags, return err; } -static struct filename *filename_parentat(struct filename *name, +static struct filename *filename_parentat(int dirfd, + struct filename *name, unsigned int flags, struct path *parent, struct qstr *last, int *type) { @@ -2111,7 +2285,7 @@ static struct filename *filename_parentat(struct filename *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; @@ -2123,7 +2297,7 @@ static struct filename *filename_parentat(struct filename *name, return name; } -static struct dentry *filename_create(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); @@ -2132,13 +2306,7 @@ static struct dentry *filename_create(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(name, 0, path, &last, &type); + name = filename_parentat(dirfd, name, 0, path, &last, &type); if (IS_ERR(name)) return ERR_CAST(name); @@ -2152,7 +2320,6 @@ static struct dentry *filename_create(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; @@ -2183,7 +2350,7 @@ out: return dentry; } -static int filename_lookup(struct filename *name, unsigned flags, +static int filename_lookup(int dirfd, struct filename *name, unsigned flags, struct path *path) { int err; @@ -2195,7 +2362,9 @@ static int filename_lookup(struct filename *name, unsigned flags, set_nameidata(&nd, name); - s = path_init(&nd, flags); + s = path_init(dirfd, &nd, flags); + if (IS_ERR(s)) + return PTR_ERR(s); while (!(err = link_path_walk(s, &nd)) && ((err = lookup_last(&nd)) > 0)) { s = trailing_symlink(&nd); @@ -2220,13 +2389,13 @@ static int filename_lookup(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(getname(pathname), 0, &path); + ret = filename_lookup(dirfd, getname(pathname), 0, &path); if (ret) return NULL; @@ -2278,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(getname(pathname), &path, lookup_flags); + dentry = filename_create(dirfd, getname(pathname), &path, lookup_flags); if (IS_ERR(dentry)) { error = PTR_ERR(dentry); goto out; @@ -2296,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; @@ -2312,7 +2478,7 @@ int rmdir (const char *pathname) struct qstr last; int type; - name = filename_parentat(getname(pathname), 0, + name = filename_parentat(dirfd, getname(pathname), 0, &path, &last, &type); if (IS_ERR(name)) return PTR_ERR(name); @@ -2351,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; @@ -2371,13 +2533,44 @@ int open(const char *pathname, int flags, ...) 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); - 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); @@ -2427,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; @@ -2442,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); @@ -2479,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(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; @@ -2520,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) { @@ -2541,7 +2751,7 @@ int symlink(const char *pathname, const char *newpath) int error; unsigned int lookup_flags = LOOKUP_DIRECTORY; - dentry = filename_create(getname(newpath), &path, lookup_flags); + dentry = filename_create(AT_FDCWD, getname(newpath), &path, lookup_flags); if (IS_ERR(dentry)) { error = PTR_ERR(dentry); goto out; @@ -2549,39 +2759,56 @@ 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, }, }; - ret = filename_lookup(getname(pathname), + 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) goto out; @@ -2600,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; @@ -2649,7 +2903,7 @@ int readlink(const char *pathname, char *buf, size_t bufsiz) const char *link; struct path path = {}; - ret = filename_lookup(getname(pathname), 0, &path); + ret = filename_lookup(dirfd, getname(pathname), 0, &path); if (ret) goto out; @@ -2679,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(getname(filename), flags, &path); + ret = filename_lookup(dirfd, getname(filename), flags, &path); if (ret) goto out; @@ -2712,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) { @@ -2740,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) { @@ -2784,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 @@ -2791,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(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; } @@ -2821,7 +3069,7 @@ int chdir(const char *pathname) struct path path; int ret; - ret = filename_lookup(getname(pathname), LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); + ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); if (ret) goto out; @@ -2839,10 +3087,7 @@ int chdir(const char *pathname) ret = 0; out: - if (ret) - errno = -ret; - - return ret; + return errno_set(ret); } EXPORT_SYMBOL(chdir); @@ -2876,13 +3121,24 @@ int popd(char *oldcwd) return ret; } -static char *get_linux_mmcblkdev(struct fs_device_d *fsdev) +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, *cdev; + struct cdev *cdevm = root_cdev->master, *cdev; int id, partnum; - cdevm = fsdev->cdev->master; - id = of_alias_get_id(cdevm->device_node, "mmc"); + 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; @@ -2894,8 +3150,7 @@ static char *get_linux_mmcblkdev(struct fs_device_d *fsdev) * in the partitions list so we need to count it instead of * skipping it. */ - if (cdev->partname && - !strcmp(cdev->partname, fsdev->cdev->partname)) + if (cdev_partname_equal(root_cdev, cdev)) return basprintf("root=/dev/mmcblk%dp%d", id, partnum); partnum++; } @@ -2903,6 +3158,23 @@ static char *get_linux_mmcblkdev(struct fs_device_d *fsdev) 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. * We do this by registering a new device on which the filesystem @@ -2911,12 +3183,12 @@ static char *get_linux_mmcblkdev(struct fs_device_d *fsdev) 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 = {}; if (d_root) { - ret = filename_lookup(getname(pathname), LOOKUP_FOLLOW, &path); + ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path); if (ret) goto out; @@ -2941,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); @@ -2987,21 +3259,17 @@ 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) { - char *str = NULL; - - if (IS_ENABLED(CONFIG_MMCBLKDEV_ROOTARG) && - fsdev->cdev->master && - cdev_is_mci_main_part_dev(fsdev->cdev->master)) - str = get_linux_mmcblkdev(fsdev); - - if (!str && fsdev->cdev->uuid[0] != 0) - str = basprintf("root=PARTUUID=%s", fsdev->cdev->uuid); + if (!fsdev->linux_rootarg) { + char *str; + str = cdev_get_linux_rootarg(fsdev->cdev); if (str) fsdev_set_linux_rootarg(fsdev, str); } @@ -3017,19 +3285,17 @@ 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; - ret = filename_lookup(getname(pathname), LOOKUP_FOLLOW, &path); + ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path); if (ret) return ret; @@ -3056,10 +3322,8 @@ int umount(const char *pathname) } } - if (!fsdev) { - errno = EFAULT; - return -EFAULT; - } + if (!fsdev) + return errno_set(-EFAULT); return fsdev_umount(fsdev); } @@ -3102,7 +3366,7 @@ void automount_remove(const char *pathname) struct path path; int ret; - ret = filename_lookup(getname(pathname), LOOKUP_FOLLOW, &path); + ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path); if (ret) return; @@ -3118,7 +3382,7 @@ int automount_add(const char *pathname, const char *cmd) struct path path; int ret; - ret = filename_lookup(getname(pathname), LOOKUP_FOLLOW, &path); + ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path); if (ret) return ret; @@ -3191,6 +3455,10 @@ static int automount_mount(struct dentry *dentry) 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; @@ -3226,14 +3494,14 @@ static int do_lookup_dentry(int argc, char *argv[]) if (argc < 2) return COMMAND_ERROR_USAGE; - ret = filename_lookup(getname(argv[1]), 0, &path); + ret = filename_lookup(AT_FDCWD, getname(argv[1]), 0, &path); if (ret) { printf("Cannot lookup path \"%s\": %s\n", argv[1], strerror(-ret)); 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); @@ -3259,7 +3527,7 @@ 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) { |