1 /* 2 * 9p 3 * 4 * Copyright IBM, Corp. 2010 5 * 6 * Authors: 7 * Gautham R Shenoy <ego@in.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "qapi/error.h" 15 #include "qemu-fsdev.h" 16 #include "qemu/queue.h" 17 #include "qemu/config-file.h" 18 #include "qemu/error-report.h" 19 #include "qemu/option.h" 20 21 /* 22 * A table to store the various file systems and their callback operations. 23 * ----------------- 24 * fstype | ops 25 * ----------------- 26 * local | local_ops 27 * . | 28 * . | 29 * . | 30 * . | 31 * ----------------- 32 * etc 33 */ 34 typedef struct FsDriverTable { 35 const char *name; 36 FileOperations *ops; 37 const char **opts; 38 } FsDriverTable; 39 40 typedef struct FsDriverListEntry { 41 FsDriverEntry fse; 42 QTAILQ_ENTRY(FsDriverListEntry) next; 43 } FsDriverListEntry; 44 45 static QTAILQ_HEAD(, FsDriverListEntry) fsdriver_entries = 46 QTAILQ_HEAD_INITIALIZER(fsdriver_entries); 47 48 #define COMMON_FS_DRIVER_OPTIONS "id", "fsdriver", "readonly" 49 50 static FsDriverTable FsDrivers[] = { 51 { 52 .name = "local", 53 .ops = &local_ops, 54 .opts = (const char * []) { 55 COMMON_FS_DRIVER_OPTIONS, 56 "security_model", 57 "path", 58 "writeout", 59 "fmode", 60 "dmode", 61 "multidevs", 62 "throttling.bps-total", 63 "throttling.bps-read", 64 "throttling.bps-write", 65 "throttling.iops-total", 66 "throttling.iops-read", 67 "throttling.iops-write", 68 "throttling.bps-total-max", 69 "throttling.bps-read-max", 70 "throttling.bps-write-max", 71 "throttling.iops-total-max", 72 "throttling.iops-read-max", 73 "throttling.iops-write-max", 74 "throttling.bps-total-max-length", 75 "throttling.bps-read-max-length", 76 "throttling.bps-write-max-length", 77 "throttling.iops-total-max-length", 78 "throttling.iops-read-max-length", 79 "throttling.iops-write-max-length", 80 "throttling.iops-size", 81 NULL 82 }, 83 }, 84 { 85 .name = "synth", 86 .ops = &synth_ops, 87 .opts = (const char * []) { 88 COMMON_FS_DRIVER_OPTIONS, 89 NULL 90 }, 91 }, 92 }; 93 94 static int validate_opt(void *opaque, const char *name, const char *value, 95 Error **errp) 96 { 97 FsDriverTable *drv = opaque; 98 const char **opt; 99 100 for (opt = drv->opts; *opt; opt++) { 101 if (!strcmp(*opt, name)) { 102 return 0; 103 } 104 } 105 106 error_setg(errp, "'%s' is invalid for fsdriver '%s'", name, drv->name); 107 return -1; 108 } 109 110 int qemu_fsdev_add(QemuOpts *opts, Error **errp) 111 { 112 int i; 113 struct FsDriverListEntry *fsle; 114 const char *fsdev_id = qemu_opts_id(opts); 115 const char *fsdriver = qemu_opt_get(opts, "fsdriver"); 116 const char *writeout = qemu_opt_get(opts, "writeout"); 117 bool ro = qemu_opt_get_bool(opts, "readonly", 0); 118 119 if (!fsdev_id) { 120 error_setg(errp, "fsdev: No id specified"); 121 return -1; 122 } 123 124 if (fsdriver) { 125 for (i = 0; i < ARRAY_SIZE(FsDrivers); i++) { 126 if (strcmp(FsDrivers[i].name, fsdriver) == 0) { 127 break; 128 } 129 } 130 131 if (i == ARRAY_SIZE(FsDrivers)) { 132 error_setg(errp, "fsdev: fsdriver %s not found", fsdriver); 133 return -1; 134 } 135 } else { 136 error_setg(errp, "fsdev: No fsdriver specified"); 137 return -1; 138 } 139 140 if (qemu_opt_foreach(opts, validate_opt, &FsDrivers[i], errp)) { 141 return -1; 142 } 143 144 fsle = g_malloc0(sizeof(*fsle)); 145 fsle->fse.fsdev_id = g_strdup(fsdev_id); 146 fsle->fse.ops = FsDrivers[i].ops; 147 if (writeout) { 148 if (!strcmp(writeout, "immediate")) { 149 fsle->fse.export_flags |= V9FS_IMMEDIATE_WRITEOUT; 150 } 151 } 152 if (ro) { 153 fsle->fse.export_flags |= V9FS_RDONLY; 154 } else { 155 fsle->fse.export_flags &= ~V9FS_RDONLY; 156 } 157 158 if (fsle->fse.ops->parse_opts) { 159 if (fsle->fse.ops->parse_opts(opts, &fsle->fse, errp)) { 160 g_free(fsle->fse.fsdev_id); 161 g_free(fsle); 162 return -1; 163 } 164 } 165 166 QTAILQ_INSERT_TAIL(&fsdriver_entries, fsle, next); 167 return 0; 168 } 169 170 FsDriverEntry *get_fsdev_fsentry(char *id) 171 { 172 if (id) { 173 struct FsDriverListEntry *fsle; 174 175 QTAILQ_FOREACH(fsle, &fsdriver_entries, next) { 176 if (strcmp(fsle->fse.fsdev_id, id) == 0) { 177 return &fsle->fse; 178 } 179 } 180 } 181 return NULL; 182 } 183