summaryrefslogtreecommitdiffstats
path: root/fs/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fs.c')
-rw-r--r--fs/fs.c892
1 files changed, 580 insertions, 312 deletions
diff --git a/fs/fs.c b/fs/fs.c
index 460fc2f7f1..3a5298649c 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -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) {