Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | // SPDX-License-Identifier: GPL-2.0 /* * Implementation of a filesystem, e.g. on a partition * * Copyright 2025 Simon Glass <sjg@chromium.org> */ #define LOG_CATEGORY UCLASS_FS #include <bootdev.h> #include <bootmeth.h> #include <dir.h> #include <dm.h> #include <fs.h> #include <dm/device-internal.h> int fs_split_path(const char *fname, char **subdirp, const char **leafp) { char *subdir, *p; if (!*fname) return log_msg_ret("fsp", -EINVAL); /* allocate space for the whole filename, for simplicity */ subdir = strdup(fname); if (!subdir) return log_msg_ret("fsp", -ENOMEM); p = strrchr(subdir, '/'); if (p) { *leafp = p + 1; *p = '\0'; } else { *leafp = fname; strcpy(subdir, "/"); } *subdirp = subdir; return 0; } int fs_lookup_dir(struct udevice *dev, const char *path, struct udevice **dirp) { struct fs_ops *ops = fs_get_ops(dev); struct udevice *dir; int ret; if (!path || !strcmp("/", path)) path = ""; /* see if we already have this directory */ device_foreach_child(dir, dev) { struct dir_uc_priv *priv; if (!device_active(dir)) continue; priv = dev_get_uclass_priv(dir); log_debug("dir %s '%s' '%s'\n", dir->name, path, priv->path); if (!strcmp(path, priv->path)) { *dirp = dir; log_debug("found: dev '%s'\n", dir->name); return 0; } } ret = ops->lookup_dir(dev, path, &dir); if (ret) return log_msg_ret("fld", ret); *dirp = dir; return 0; } int fs_mount(struct udevice *dev) { struct fs_ops *ops = fs_get_ops(dev); int ret; ret = ops->mount(dev); if (ret) return log_msg_ret("fsm", ret); ret = bootdev_setup_for_dev(dev, "fs_bootdev"); if (ret) return log_msg_ret("fss", ret); return 0; } int fs_unmount(struct udevice *dev) { struct fs_ops *ops = fs_get_ops(dev); return ops->unmount(dev); } static int fs_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, struct bootflow *bflow) { struct udevice *fsdev = dev_get_parent(dev); int ret; log_debug("get_bootflow fs '%s'\n", fsdev->name); /* for now, always fail here as we don't have FS support in bootmeths */ return -ENOENT; ret = bootmeth_check(bflow->method, iter); if (ret) return log_msg_ret("check", ret); return 0; } static int fs_bootdev_bind(struct udevice *dev) { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); /* * we don't know what priority to give this, so pick something a little * slow for now */ ucp->prio = BOOTDEVP_3_INTERNAL_SLOW; return 0; } static int fs_bootdev_hunt(struct bootdev_hunter *info, bool show) { struct udevice *dev; int ret; /* mount all filesystems, which will create bootdevs for each */ uclass_foreach_dev_probe(UCLASS_FS, dev) { ret = fs_mount(dev); if (ret) log_warning("Failed to mount filesystem '%s'\n", dev->name); } return 0; } struct bootdev_ops fs_bootdev_ops = { .get_bootflow = fs_get_bootflow, }; static const struct udevice_id fs_bootdev_ids[] = { { .compatible = "u-boot,bootdev-fs" }, { } }; U_BOOT_DRIVER(fs_bootdev) = { .name = "fs_bootdev", .id = UCLASS_BOOTDEV, .ops = &fs_bootdev_ops, .bind = fs_bootdev_bind, .of_match = fs_bootdev_ids, }; BOOTDEV_HUNTER(fs_bootdev_hunter) = { .prio = BOOTDEVP_3_INTERNAL_SLOW, .uclass = UCLASS_FS, .hunt = fs_bootdev_hunt, .drv = DM_DRIVER_REF(fs_bootdev), }; UCLASS_DRIVER(fs) = { .name = "fs", .id = UCLASS_FS, .per_device_auto = sizeof(struct fs_priv), .per_device_plat_auto = sizeof(struct fs_plat), }; |