24#include <sys/kernel.h> 25#include <sys/sysctl.h> 26#include <sys/malloc.h> 27#include <sys/sysctl.h> 28#include <machine/md_var.h> 29#include <sys/ctype.h> 30 31static MALLOC_DEFINE(M_DISK, "disk", "disk data"); 32 33static d_strategy_t diskstrategy; 34static d_open_t diskopen; 35static d_close_t diskclose; 36static d_ioctl_t diskioctl; 37static d_psize_t diskpsize; 38 39static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 40 41void disk_dev_synth(dev_t dev); 42 43void 44disk_dev_synth(dev_t dev) 45{ 46 struct disk *dp; 47 int u, s, p; 48 dev_t pdev; 49 50 if (dksparebits(dev)) 51 return; 52 LIST_FOREACH(dp, &disklist, d_list) { 53 if (major(dev) != dp->d_devsw->d_maj) 54 continue; 55 u = dkunit(dev); 56 p = RAW_PART; 57 s = WHOLE_DISK_SLICE; 58 pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 59 if (pdev->si_devsw == NULL) 60 return; /* Probably a unit we don't have */ 61 s = dkslice(dev); 62 p = dkpart(dev); 63 if (s == WHOLE_DISK_SLICE && p == RAW_PART) { 64 /* XXX: actually should not happen */ 65 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 66 UID_ROOT, GID_OPERATOR, 0640, "%s%d", 67 dp->d_devsw->d_name, u); 68 dev_depends(pdev, dev); 69 return; 70 } 71 if (s == COMPATIBILITY_SLICE) { 72 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 73 UID_ROOT, GID_OPERATOR, 0640, "%s%d%c", 74 dp->d_devsw->d_name, u, 'a' + p); 75 dev_depends(pdev, dev); 76 return; 77 } 78 if (p != RAW_PART) { 79 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 80 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 81 dp->d_devsw->d_name, u, s - BASE_SLICE + 1, 82 'a' + p); 83 } else { 84 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 85 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d", 86 dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 87 make_dev_alias(dev, "%s%ds%dc", 88 dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 89 } 90 dev_depends(pdev, dev); 91 return; 92 } 93} 94 95static void 96disk_clone(void *arg, char *name, int namelen, dev_t *dev) 97{ 98 struct disk *dp; 99 char const *d; 100 char *e; 101 int j, u, s, p; 102 dev_t pdev; 103 104 if (*dev != NODEV) 105 return; 106 107 LIST_FOREACH(dp, &disklist, d_list) { 108 d = dp->d_devsw->d_name; 109 j = dev_stdclone(name, &e, d, &u); 110 if (j == 0) 111 continue; 112 if (u > DKMAXUNIT) 113 continue; 114 p = RAW_PART; 115 s = WHOLE_DISK_SLICE; 116 pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 117 if (pdev->si_disk == NULL) 118 continue; 119 if (*e != '\0') { 120 j = dev_stdclone(e, &e, "s", &s); 121 if (j == 0) 122 s = COMPATIBILITY_SLICE; 123 else if (j == 1 || j == 2) 124 s += BASE_SLICE - 1; 125 if (!*e) 126 ; /* ad0s1 case */ 127 else if (e[1] != '\0') 128 return; /* can never be a disk name */ 129 else if (*e < 'a' || *e > 'h') 130 return; /* can never be a disk name */ 131 else 132 p = *e - 'a'; 133 } 134 if (s == WHOLE_DISK_SLICE && p == RAW_PART) { 135 return; 136 } else if (s >= BASE_SLICE && p != RAW_PART) { 137 *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 138 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 139 pdev->si_devsw->d_name, u, s - BASE_SLICE + 1, 140 p + 'a'); 141 } else if (s >= BASE_SLICE) { 142 *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 143 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d", 144 pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 145 make_dev_alias(*dev, "%s%ds%dc", 146 pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 147 } else { 148 *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 149 UID_ROOT, GID_OPERATOR, 0640, "%s%d%c", 150 pdev->si_devsw->d_name, u, p + 'a'); 151 } 152 dev_depends(pdev, *dev); 153 return; 154 } 155} 156 157static void 158inherit_raw(dev_t pdev, dev_t dev) 159{ 160 dev->si_disk = pdev->si_disk; 161 dev->si_drv1 = pdev->si_drv1; 162 dev->si_drv2 = pdev->si_drv2; 163 dev->si_iosize_max = pdev->si_iosize_max; 164 dev->si_bsize_phys = pdev->si_bsize_phys; 165 dev->si_bsize_best = pdev->si_bsize_best; 166} 167 168dev_t 169disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 170{ 171 static int once; 172 dev_t dev; 173 174 if (!once) { 175 EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 176 once++; 177 } 178 179 bzero(dp, sizeof(*dp)); 180 dp->d_label = malloc(sizeof *dp->d_label, M_DEVBUF, M_WAITOK|M_ZERO); 181 182 if (proto->d_open != diskopen) { 183 *proto = *cdevsw; 184 proto->d_open = diskopen; 185 proto->d_close = diskclose; 186 proto->d_ioctl = diskioctl; 187 proto->d_strategy = diskstrategy; 188 proto->d_psize = diskpsize; 189 } 190 191 if (bootverbose) 192 printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 193 dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 194 UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 195 196 dev->si_disk = dp; 197 dp->d_dev = dev; 198 dp->d_dsflags = flags; 199 dp->d_devsw = cdevsw; 200 LIST_INSERT_HEAD(&disklist, dp, d_list); 201 202 return (dev); 203} 204 205static int 206diskdumpconf(u_int onoff, dev_t dev, struct disk *dp) 207{ 208 struct dumperinfo di; 209 struct disklabel *dl; 210 211 if (!onoff) 212 return(set_dumper(NULL)); 213 dl = dsgetlabel(dev, dp->d_slice); 214 if (!dl) 215 return (ENXIO); 216 bzero(&di, sizeof di); 217 di.dumper = (dumper_t *)dp->d_devsw->d_dump; 218 di.priv = dp->d_dev; 219 di.blocksize = dl->d_secsize; 220 di.mediaoffset = (off_t)(dl->d_partitions[dkpart(dev)].p_offset + 221 dp->d_slice->dss_slices[dkslice(dev)].ds_offset) * DEV_BSIZE; 222 di.mediasize = 223 (off_t)(dl->d_partitions[dkpart(dev)].p_size) * DEV_BSIZE; 224 if (di.mediasize == 0) 225 return (EINVAL); 226 return(set_dumper(&di)); 227} 228 229void 230disk_invalidate (struct disk *disk) 231{ 232 if (disk->d_slice) 233 dsgone(&disk->d_slice); 234} 235 236void 237disk_destroy(dev_t dev) 238{ 239 LIST_REMOVE(dev->si_disk, d_list); 240 free(dev->si_disk->d_label, M_DEVBUF); 241 bzero(dev->si_disk, sizeof(*dev->si_disk)); 242 dev->si_disk = NULL; 243 destroy_dev(dev); 244 return; 245} 246 247struct disk * 248disk_enumerate(struct disk *disk) 249{ 250 if (!disk) 251 return (LIST_FIRST(&disklist)); 252 else 253 return (LIST_NEXT(disk, d_list)); 254} 255 256static int 257sysctl_disks(SYSCTL_HANDLER_ARGS) 258{ 259 struct disk *disk; 260 int error, first; 261 262 disk = NULL; 263 first = 1; 264 265 while ((disk = disk_enumerate(disk))) { 266 if (!first) { 267 error = SYSCTL_OUT(req, " ", 1); 268 if (error) 269 return error; 270 } else { 271 first = 0; 272 } 273 error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 274 if (error) 275 return error; 276 } 277 error = SYSCTL_OUT(req, "", 1); 278 return error; 279} 280 281SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, 0, 282 sysctl_disks, "A", "names of available disks"); 283 284/* 285 * The cdevsw functions 286 */ 287 288static int 289diskopen(dev_t dev, int oflags, int devtype, struct thread *td) 290{ 291 dev_t pdev; 292 struct disk *dp; 293 int error; 294 295 error = 0; 296 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 297 298 dp = pdev->si_disk; 299 if (!dp) 300 return (ENXIO); 301 302 while (dp->d_flags & DISKFLAG_LOCK) { 303 dp->d_flags |= DISKFLAG_WANTED; 304 error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 305 if (error) 306 return (error); 307 } 308 dp->d_flags |= DISKFLAG_LOCK; 309 310 if (!dsisopen(dp->d_slice)) { 311 if (!pdev->si_iosize_max) 312 pdev->si_iosize_max = dev->si_iosize_max; 313 error = dp->d_devsw->d_open(pdev, oflags, devtype, td); 314 dp->d_label->d_secsize = dp->d_sectorsize; 315 dp->d_label->d_secperunit = dp->d_mediasize / dp->d_sectorsize; 316 } 317 318 /* Inherit properties from the whole/raw dev_t */ 319 inherit_raw(pdev, dev); 320 321 if (error) 322 goto out; 323 324 error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, dp->d_label); 325 326 if (!dsisopen(dp->d_slice)) 327 dp->d_devsw->d_close(pdev, oflags, devtype, td); 328out: 329 dp->d_flags &= ~DISKFLAG_LOCK; 330 if (dp->d_flags & DISKFLAG_WANTED) { 331 dp->d_flags &= ~DISKFLAG_WANTED; 332 wakeup(dp); 333 } 334 335 return(error); 336} 337 338static int 339diskclose(dev_t dev, int fflag, int devtype, struct thread *td) 340{ 341 struct disk *dp; 342 int error; 343 dev_t pdev; 344 345 error = 0; 346 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 347 dp = pdev->si_disk; 348 if (!dp) 349 return (ENXIO); 350 dsclose(dev, devtype, dp->d_slice); 351 if (!dsisopen(dp->d_slice)) 352 error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td); 353 return (error); 354} 355 356static void 357diskstrategy(struct bio *bp) 358{ 359 dev_t pdev; 360 struct disk *dp; 361 362 pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 363 dp = pdev->si_disk; 364 bp->bio_resid = bp->bio_bcount; 365 if (dp != bp->bio_dev->si_disk) 366 inherit_raw(pdev, bp->bio_dev); 367 368 if (!dp) { 369 biofinish(bp, NULL, ENXIO); 370 return; 371 } 372 373 if (dscheck(bp, dp->d_slice) <= 0) { 374 biodone(bp); 375 return; 376 } 377 378 if (bp->bio_bcount == 0) { 379 biodone(bp); 380 return; 381 } 382 383 KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 384 KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 385 dp->d_devsw->d_strategy(bp); 386 return; 387 388} 389 390static int 391diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 392{ 393 struct disk *dp; 394 int error; 395 u_int u; 396 dev_t pdev; 397 398 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 399 dp = pdev->si_disk; 400 if (!dp) 401 return (ENXIO); 402 if (cmd == DIOCSKERNELDUMP) { 403 u = *(u_int *)data; 404 return (diskdumpconf(u, dev, dp)); 405 } 406 if (cmd == DIOCGFRONTSTUFF) { 407 *(off_t *)data = 8192; /* XXX: crude but enough) */ 408 return (0); 409 } 410 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 411 if (error == ENOIOCTL) 412 error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td); 413 return (error); 414} 415 416static int 417diskpsize(dev_t dev) 418{ 419 struct disk *dp; 420 dev_t pdev; 421 422 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 423 dp = pdev->si_disk; 424 if (!dp) 425 return (-1); 426 if (dp != dev->si_disk) { 427 dev->si_drv1 = pdev->si_drv1; 428 dev->si_drv2 = pdev->si_drv2; 429 /* XXX: don't set bp->b_dev->si_disk (?) */ 430 } 431 return (dssize(dev, &dp->d_slice)); 432} 433 434SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 435 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 436 437SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 438 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 439 440SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 441 0, sizeof(struct disk), "sizeof(struct disk)"); 442
| 24#include <sys/kernel.h> 25#include <sys/sysctl.h> 26#include <sys/malloc.h> 27#include <sys/sysctl.h> 28#include <machine/md_var.h> 29#include <sys/ctype.h> 30 31static MALLOC_DEFINE(M_DISK, "disk", "disk data"); 32 33static d_strategy_t diskstrategy; 34static d_open_t diskopen; 35static d_close_t diskclose; 36static d_ioctl_t diskioctl; 37static d_psize_t diskpsize; 38 39static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 40 41void disk_dev_synth(dev_t dev); 42 43void 44disk_dev_synth(dev_t dev) 45{ 46 struct disk *dp; 47 int u, s, p; 48 dev_t pdev; 49 50 if (dksparebits(dev)) 51 return; 52 LIST_FOREACH(dp, &disklist, d_list) { 53 if (major(dev) != dp->d_devsw->d_maj) 54 continue; 55 u = dkunit(dev); 56 p = RAW_PART; 57 s = WHOLE_DISK_SLICE; 58 pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 59 if (pdev->si_devsw == NULL) 60 return; /* Probably a unit we don't have */ 61 s = dkslice(dev); 62 p = dkpart(dev); 63 if (s == WHOLE_DISK_SLICE && p == RAW_PART) { 64 /* XXX: actually should not happen */ 65 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 66 UID_ROOT, GID_OPERATOR, 0640, "%s%d", 67 dp->d_devsw->d_name, u); 68 dev_depends(pdev, dev); 69 return; 70 } 71 if (s == COMPATIBILITY_SLICE) { 72 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 73 UID_ROOT, GID_OPERATOR, 0640, "%s%d%c", 74 dp->d_devsw->d_name, u, 'a' + p); 75 dev_depends(pdev, dev); 76 return; 77 } 78 if (p != RAW_PART) { 79 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 80 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 81 dp->d_devsw->d_name, u, s - BASE_SLICE + 1, 82 'a' + p); 83 } else { 84 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 85 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d", 86 dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 87 make_dev_alias(dev, "%s%ds%dc", 88 dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 89 } 90 dev_depends(pdev, dev); 91 return; 92 } 93} 94 95static void 96disk_clone(void *arg, char *name, int namelen, dev_t *dev) 97{ 98 struct disk *dp; 99 char const *d; 100 char *e; 101 int j, u, s, p; 102 dev_t pdev; 103 104 if (*dev != NODEV) 105 return; 106 107 LIST_FOREACH(dp, &disklist, d_list) { 108 d = dp->d_devsw->d_name; 109 j = dev_stdclone(name, &e, d, &u); 110 if (j == 0) 111 continue; 112 if (u > DKMAXUNIT) 113 continue; 114 p = RAW_PART; 115 s = WHOLE_DISK_SLICE; 116 pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 117 if (pdev->si_disk == NULL) 118 continue; 119 if (*e != '\0') { 120 j = dev_stdclone(e, &e, "s", &s); 121 if (j == 0) 122 s = COMPATIBILITY_SLICE; 123 else if (j == 1 || j == 2) 124 s += BASE_SLICE - 1; 125 if (!*e) 126 ; /* ad0s1 case */ 127 else if (e[1] != '\0') 128 return; /* can never be a disk name */ 129 else if (*e < 'a' || *e > 'h') 130 return; /* can never be a disk name */ 131 else 132 p = *e - 'a'; 133 } 134 if (s == WHOLE_DISK_SLICE && p == RAW_PART) { 135 return; 136 } else if (s >= BASE_SLICE && p != RAW_PART) { 137 *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 138 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 139 pdev->si_devsw->d_name, u, s - BASE_SLICE + 1, 140 p + 'a'); 141 } else if (s >= BASE_SLICE) { 142 *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 143 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d", 144 pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 145 make_dev_alias(*dev, "%s%ds%dc", 146 pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 147 } else { 148 *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 149 UID_ROOT, GID_OPERATOR, 0640, "%s%d%c", 150 pdev->si_devsw->d_name, u, p + 'a'); 151 } 152 dev_depends(pdev, *dev); 153 return; 154 } 155} 156 157static void 158inherit_raw(dev_t pdev, dev_t dev) 159{ 160 dev->si_disk = pdev->si_disk; 161 dev->si_drv1 = pdev->si_drv1; 162 dev->si_drv2 = pdev->si_drv2; 163 dev->si_iosize_max = pdev->si_iosize_max; 164 dev->si_bsize_phys = pdev->si_bsize_phys; 165 dev->si_bsize_best = pdev->si_bsize_best; 166} 167 168dev_t 169disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 170{ 171 static int once; 172 dev_t dev; 173 174 if (!once) { 175 EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 176 once++; 177 } 178 179 bzero(dp, sizeof(*dp)); 180 dp->d_label = malloc(sizeof *dp->d_label, M_DEVBUF, M_WAITOK|M_ZERO); 181 182 if (proto->d_open != diskopen) { 183 *proto = *cdevsw; 184 proto->d_open = diskopen; 185 proto->d_close = diskclose; 186 proto->d_ioctl = diskioctl; 187 proto->d_strategy = diskstrategy; 188 proto->d_psize = diskpsize; 189 } 190 191 if (bootverbose) 192 printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 193 dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 194 UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 195 196 dev->si_disk = dp; 197 dp->d_dev = dev; 198 dp->d_dsflags = flags; 199 dp->d_devsw = cdevsw; 200 LIST_INSERT_HEAD(&disklist, dp, d_list); 201 202 return (dev); 203} 204 205static int 206diskdumpconf(u_int onoff, dev_t dev, struct disk *dp) 207{ 208 struct dumperinfo di; 209 struct disklabel *dl; 210 211 if (!onoff) 212 return(set_dumper(NULL)); 213 dl = dsgetlabel(dev, dp->d_slice); 214 if (!dl) 215 return (ENXIO); 216 bzero(&di, sizeof di); 217 di.dumper = (dumper_t *)dp->d_devsw->d_dump; 218 di.priv = dp->d_dev; 219 di.blocksize = dl->d_secsize; 220 di.mediaoffset = (off_t)(dl->d_partitions[dkpart(dev)].p_offset + 221 dp->d_slice->dss_slices[dkslice(dev)].ds_offset) * DEV_BSIZE; 222 di.mediasize = 223 (off_t)(dl->d_partitions[dkpart(dev)].p_size) * DEV_BSIZE; 224 if (di.mediasize == 0) 225 return (EINVAL); 226 return(set_dumper(&di)); 227} 228 229void 230disk_invalidate (struct disk *disk) 231{ 232 if (disk->d_slice) 233 dsgone(&disk->d_slice); 234} 235 236void 237disk_destroy(dev_t dev) 238{ 239 LIST_REMOVE(dev->si_disk, d_list); 240 free(dev->si_disk->d_label, M_DEVBUF); 241 bzero(dev->si_disk, sizeof(*dev->si_disk)); 242 dev->si_disk = NULL; 243 destroy_dev(dev); 244 return; 245} 246 247struct disk * 248disk_enumerate(struct disk *disk) 249{ 250 if (!disk) 251 return (LIST_FIRST(&disklist)); 252 else 253 return (LIST_NEXT(disk, d_list)); 254} 255 256static int 257sysctl_disks(SYSCTL_HANDLER_ARGS) 258{ 259 struct disk *disk; 260 int error, first; 261 262 disk = NULL; 263 first = 1; 264 265 while ((disk = disk_enumerate(disk))) { 266 if (!first) { 267 error = SYSCTL_OUT(req, " ", 1); 268 if (error) 269 return error; 270 } else { 271 first = 0; 272 } 273 error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 274 if (error) 275 return error; 276 } 277 error = SYSCTL_OUT(req, "", 1); 278 return error; 279} 280 281SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, 0, 282 sysctl_disks, "A", "names of available disks"); 283 284/* 285 * The cdevsw functions 286 */ 287 288static int 289diskopen(dev_t dev, int oflags, int devtype, struct thread *td) 290{ 291 dev_t pdev; 292 struct disk *dp; 293 int error; 294 295 error = 0; 296 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 297 298 dp = pdev->si_disk; 299 if (!dp) 300 return (ENXIO); 301 302 while (dp->d_flags & DISKFLAG_LOCK) { 303 dp->d_flags |= DISKFLAG_WANTED; 304 error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 305 if (error) 306 return (error); 307 } 308 dp->d_flags |= DISKFLAG_LOCK; 309 310 if (!dsisopen(dp->d_slice)) { 311 if (!pdev->si_iosize_max) 312 pdev->si_iosize_max = dev->si_iosize_max; 313 error = dp->d_devsw->d_open(pdev, oflags, devtype, td); 314 dp->d_label->d_secsize = dp->d_sectorsize; 315 dp->d_label->d_secperunit = dp->d_mediasize / dp->d_sectorsize; 316 } 317 318 /* Inherit properties from the whole/raw dev_t */ 319 inherit_raw(pdev, dev); 320 321 if (error) 322 goto out; 323 324 error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, dp->d_label); 325 326 if (!dsisopen(dp->d_slice)) 327 dp->d_devsw->d_close(pdev, oflags, devtype, td); 328out: 329 dp->d_flags &= ~DISKFLAG_LOCK; 330 if (dp->d_flags & DISKFLAG_WANTED) { 331 dp->d_flags &= ~DISKFLAG_WANTED; 332 wakeup(dp); 333 } 334 335 return(error); 336} 337 338static int 339diskclose(dev_t dev, int fflag, int devtype, struct thread *td) 340{ 341 struct disk *dp; 342 int error; 343 dev_t pdev; 344 345 error = 0; 346 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 347 dp = pdev->si_disk; 348 if (!dp) 349 return (ENXIO); 350 dsclose(dev, devtype, dp->d_slice); 351 if (!dsisopen(dp->d_slice)) 352 error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td); 353 return (error); 354} 355 356static void 357diskstrategy(struct bio *bp) 358{ 359 dev_t pdev; 360 struct disk *dp; 361 362 pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 363 dp = pdev->si_disk; 364 bp->bio_resid = bp->bio_bcount; 365 if (dp != bp->bio_dev->si_disk) 366 inherit_raw(pdev, bp->bio_dev); 367 368 if (!dp) { 369 biofinish(bp, NULL, ENXIO); 370 return; 371 } 372 373 if (dscheck(bp, dp->d_slice) <= 0) { 374 biodone(bp); 375 return; 376 } 377 378 if (bp->bio_bcount == 0) { 379 biodone(bp); 380 return; 381 } 382 383 KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 384 KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 385 dp->d_devsw->d_strategy(bp); 386 return; 387 388} 389 390static int 391diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 392{ 393 struct disk *dp; 394 int error; 395 u_int u; 396 dev_t pdev; 397 398 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 399 dp = pdev->si_disk; 400 if (!dp) 401 return (ENXIO); 402 if (cmd == DIOCSKERNELDUMP) { 403 u = *(u_int *)data; 404 return (diskdumpconf(u, dev, dp)); 405 } 406 if (cmd == DIOCGFRONTSTUFF) { 407 *(off_t *)data = 8192; /* XXX: crude but enough) */ 408 return (0); 409 } 410 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 411 if (error == ENOIOCTL) 412 error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td); 413 return (error); 414} 415 416static int 417diskpsize(dev_t dev) 418{ 419 struct disk *dp; 420 dev_t pdev; 421 422 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 423 dp = pdev->si_disk; 424 if (!dp) 425 return (-1); 426 if (dp != dev->si_disk) { 427 dev->si_drv1 = pdev->si_drv1; 428 dev->si_drv2 = pdev->si_drv2; 429 /* XXX: don't set bp->b_dev->si_disk (?) */ 430 } 431 return (dssize(dev, &dp->d_slice)); 432} 433 434SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 435 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 436 437SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 438 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 439 440SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 441 0, sizeof(struct disk), "sizeof(struct disk)"); 442
|
444 445/*- 446 * Disk error is the preface to plaintive error messages 447 * about failing disk transfers. It prints messages of the form 448 * "hp0g: BLABLABLA cmd=read fsbn 12345 of 12344-12347" 449 * blkdone should be -1 if the position of the error is unknown. 450 * The message is printed with printf. 451 */ 452void 453disk_err(struct bio *bp, const char *what, int blkdone, int nl) 454{ 455 daddr_t sn; 456 457 printf("%s: %s", devtoname(bp->bio_dev), what); 458 switch(bp->bio_cmd) { 459 case BIO_READ: printf("cmd=read"); break; 460 case BIO_WRITE: printf("cmd=write"); break; 461 case BIO_DELETE: printf("cmd=delete"); break; 462 case BIO_GETATTR: printf("cmd=getattr"); break; 463 case BIO_SETATTR: printf("cmd=setattr"); break; 464 default: printf("cmd=%x", bp->bio_cmd); break; 465 } 466 sn = bp->bio_blkno; 467 if (bp->bio_bcount <= DEV_BSIZE) { 468 printf("fsbn %jd%s", (intmax_t)sn, nl ? "\n" : ""); 469 return; 470 } 471 if (blkdone >= 0) { 472 sn += blkdone; 473 printf("fsbn %jd of ", (intmax_t)sn); 474 } 475 printf("%jd-%jd", (intmax_t)bp->bio_blkno, 476 (intmax_t)(bp->bio_blkno + (bp->bio_bcount - 1) / DEV_BSIZE)); 477 if (nl) 478 printf("\n"); 479} 480 481#ifdef notquite 482/* 483 * Mutex to use when delaying niced I/O bound processes in bioq_disksort(). 484 */ 485static struct mtx dksort_mtx; 486static void 487dksort_init(void) 488{ 489 490 mtx_init(&dksort_mtx, "dksort", NULL, MTX_DEF); 491} 492SYSINIT(dksort, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dksort_init, NULL) 493#endif 494 495/* 496 * Seek sort for disks. 497 * 498 * The buf_queue keep two queues, sorted in ascending block order. The first 499 * queue holds those requests which are positioned after the current block 500 * (in the first request); the second, which starts at queue->switch_point, 501 * holds requests which came in after their block number was passed. Thus 502 * we implement a one way scan, retracting after reaching the end of the drive 503 * to the first request on the second queue, at which time it becomes the 504 * first queue. 505 * 506 * A one-way scan is natural because of the way UNIX read-ahead blocks are 507 * allocated. 508 */ 509 510void 511bioq_disksort(bioq, bp) 512 struct bio_queue_head *bioq; 513 struct bio *bp; 514{ 515 struct bio *bq; 516 struct bio *bn; 517 struct bio *be; 518 519#ifdef notquite 520 struct thread *td = curthread; 521 522 if (td && td->td_ksegrp->kg_nice > 0) { 523 TAILQ_FOREACH(bn, &bioq->queue, bio_queue) 524 if (BIOTOBUF(bp)->b_vp != BIOTOBUF(bn)->b_vp) 525 break; 526 if (bn != NULL) { 527 mtx_lock(&dksort_mtx); 528 msleep(&dksort_mtx, &dksort_mtx, 529 PPAUSE | PCATCH | PDROP, "ioslow", 530 td->td_ksegrp->kg_nice); 531 } 532 } 533#endif 534 if (!atomic_cmpset_int(&bioq->busy, 0, 1)) 535 panic("Recursing in bioq_disksort()"); 536 be = TAILQ_LAST(&bioq->queue, bio_queue); 537 /* 538 * If the queue is empty or we are an 539 * ordered transaction, then it's easy. 540 */ 541 if ((bq = bioq_first(bioq)) == NULL) { 542 bioq_insert_tail(bioq, bp); 543 bioq->busy = 0; 544 return; 545 } else if (bioq->insert_point != NULL) { 546 547 /* 548 * A certain portion of the list is 549 * "locked" to preserve ordering, so 550 * we can only insert after the insert 551 * point. 552 */ 553 bq = bioq->insert_point; 554 } else { 555 556 /* 557 * If we lie before the last removed (currently active) 558 * request, and are not inserting ourselves into the 559 * "locked" portion of the list, then we must add ourselves 560 * to the second request list. 561 */ 562 if (bp->bio_pblkno < bioq->last_pblkno) { 563 564 bq = bioq->switch_point; 565 /* 566 * If we are starting a new secondary list, 567 * then it's easy. 568 */ 569 if (bq == NULL) { 570 bioq->switch_point = bp; 571 bioq_insert_tail(bioq, bp); 572 bioq->busy = 0; 573 return; 574 } 575 /* 576 * If we lie ahead of the current switch point, 577 * insert us before the switch point and move 578 * the switch point. 579 */ 580 if (bp->bio_pblkno < bq->bio_pblkno) { 581 bioq->switch_point = bp; 582 TAILQ_INSERT_BEFORE(bq, bp, bio_queue); 583 bioq->busy = 0; 584 return; 585 } 586 } else { 587 if (bioq->switch_point != NULL) 588 be = TAILQ_PREV(bioq->switch_point, 589 bio_queue, bio_queue); 590 /* 591 * If we lie between last_pblkno and bq, 592 * insert before bq. 593 */ 594 if (bp->bio_pblkno < bq->bio_pblkno) { 595 TAILQ_INSERT_BEFORE(bq, bp, bio_queue); 596 bioq->busy = 0; 597 return; 598 } 599 } 600 } 601 602 /* 603 * Request is at/after our current position in the list. 604 * Optimize for sequential I/O by seeing if we go at the tail. 605 */ 606 if (bp->bio_pblkno > be->bio_pblkno) { 607 TAILQ_INSERT_AFTER(&bioq->queue, be, bp, bio_queue); 608 bioq->busy = 0; 609 return; 610 } 611 612 /* Otherwise, insertion sort */ 613 while ((bn = TAILQ_NEXT(bq, bio_queue)) != NULL) { 614 615 /* 616 * We want to go after the current request if it is the end 617 * of the first request list, or if the next request is a 618 * larger cylinder than our request. 619 */ 620 if (bn == bioq->switch_point 621 || bp->bio_pblkno < bn->bio_pblkno) 622 break; 623 bq = bn; 624 } 625 TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue); 626 bioq->busy = 0; 627} 628 629
| 444 445/*- 446 * Disk error is the preface to plaintive error messages 447 * about failing disk transfers. It prints messages of the form 448 * "hp0g: BLABLABLA cmd=read fsbn 12345 of 12344-12347" 449 * blkdone should be -1 if the position of the error is unknown. 450 * The message is printed with printf. 451 */ 452void 453disk_err(struct bio *bp, const char *what, int blkdone, int nl) 454{ 455 daddr_t sn; 456 457 printf("%s: %s", devtoname(bp->bio_dev), what); 458 switch(bp->bio_cmd) { 459 case BIO_READ: printf("cmd=read"); break; 460 case BIO_WRITE: printf("cmd=write"); break; 461 case BIO_DELETE: printf("cmd=delete"); break; 462 case BIO_GETATTR: printf("cmd=getattr"); break; 463 case BIO_SETATTR: printf("cmd=setattr"); break; 464 default: printf("cmd=%x", bp->bio_cmd); break; 465 } 466 sn = bp->bio_blkno; 467 if (bp->bio_bcount <= DEV_BSIZE) { 468 printf("fsbn %jd%s", (intmax_t)sn, nl ? "\n" : ""); 469 return; 470 } 471 if (blkdone >= 0) { 472 sn += blkdone; 473 printf("fsbn %jd of ", (intmax_t)sn); 474 } 475 printf("%jd-%jd", (intmax_t)bp->bio_blkno, 476 (intmax_t)(bp->bio_blkno + (bp->bio_bcount - 1) / DEV_BSIZE)); 477 if (nl) 478 printf("\n"); 479} 480 481#ifdef notquite 482/* 483 * Mutex to use when delaying niced I/O bound processes in bioq_disksort(). 484 */ 485static struct mtx dksort_mtx; 486static void 487dksort_init(void) 488{ 489 490 mtx_init(&dksort_mtx, "dksort", NULL, MTX_DEF); 491} 492SYSINIT(dksort, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dksort_init, NULL) 493#endif 494 495/* 496 * Seek sort for disks. 497 * 498 * The buf_queue keep two queues, sorted in ascending block order. The first 499 * queue holds those requests which are positioned after the current block 500 * (in the first request); the second, which starts at queue->switch_point, 501 * holds requests which came in after their block number was passed. Thus 502 * we implement a one way scan, retracting after reaching the end of the drive 503 * to the first request on the second queue, at which time it becomes the 504 * first queue. 505 * 506 * A one-way scan is natural because of the way UNIX read-ahead blocks are 507 * allocated. 508 */ 509 510void 511bioq_disksort(bioq, bp) 512 struct bio_queue_head *bioq; 513 struct bio *bp; 514{ 515 struct bio *bq; 516 struct bio *bn; 517 struct bio *be; 518 519#ifdef notquite 520 struct thread *td = curthread; 521 522 if (td && td->td_ksegrp->kg_nice > 0) { 523 TAILQ_FOREACH(bn, &bioq->queue, bio_queue) 524 if (BIOTOBUF(bp)->b_vp != BIOTOBUF(bn)->b_vp) 525 break; 526 if (bn != NULL) { 527 mtx_lock(&dksort_mtx); 528 msleep(&dksort_mtx, &dksort_mtx, 529 PPAUSE | PCATCH | PDROP, "ioslow", 530 td->td_ksegrp->kg_nice); 531 } 532 } 533#endif 534 if (!atomic_cmpset_int(&bioq->busy, 0, 1)) 535 panic("Recursing in bioq_disksort()"); 536 be = TAILQ_LAST(&bioq->queue, bio_queue); 537 /* 538 * If the queue is empty or we are an 539 * ordered transaction, then it's easy. 540 */ 541 if ((bq = bioq_first(bioq)) == NULL) { 542 bioq_insert_tail(bioq, bp); 543 bioq->busy = 0; 544 return; 545 } else if (bioq->insert_point != NULL) { 546 547 /* 548 * A certain portion of the list is 549 * "locked" to preserve ordering, so 550 * we can only insert after the insert 551 * point. 552 */ 553 bq = bioq->insert_point; 554 } else { 555 556 /* 557 * If we lie before the last removed (currently active) 558 * request, and are not inserting ourselves into the 559 * "locked" portion of the list, then we must add ourselves 560 * to the second request list. 561 */ 562 if (bp->bio_pblkno < bioq->last_pblkno) { 563 564 bq = bioq->switch_point; 565 /* 566 * If we are starting a new secondary list, 567 * then it's easy. 568 */ 569 if (bq == NULL) { 570 bioq->switch_point = bp; 571 bioq_insert_tail(bioq, bp); 572 bioq->busy = 0; 573 return; 574 } 575 /* 576 * If we lie ahead of the current switch point, 577 * insert us before the switch point and move 578 * the switch point. 579 */ 580 if (bp->bio_pblkno < bq->bio_pblkno) { 581 bioq->switch_point = bp; 582 TAILQ_INSERT_BEFORE(bq, bp, bio_queue); 583 bioq->busy = 0; 584 return; 585 } 586 } else { 587 if (bioq->switch_point != NULL) 588 be = TAILQ_PREV(bioq->switch_point, 589 bio_queue, bio_queue); 590 /* 591 * If we lie between last_pblkno and bq, 592 * insert before bq. 593 */ 594 if (bp->bio_pblkno < bq->bio_pblkno) { 595 TAILQ_INSERT_BEFORE(bq, bp, bio_queue); 596 bioq->busy = 0; 597 return; 598 } 599 } 600 } 601 602 /* 603 * Request is at/after our current position in the list. 604 * Optimize for sequential I/O by seeing if we go at the tail. 605 */ 606 if (bp->bio_pblkno > be->bio_pblkno) { 607 TAILQ_INSERT_AFTER(&bioq->queue, be, bp, bio_queue); 608 bioq->busy = 0; 609 return; 610 } 611 612 /* Otherwise, insertion sort */ 613 while ((bn = TAILQ_NEXT(bq, bio_queue)) != NULL) { 614 615 /* 616 * We want to go after the current request if it is the end 617 * of the first request list, or if the next request is a 618 * larger cylinder than our request. 619 */ 620 if (bn == bioq->switch_point 621 || bp->bio_pblkno < bn->bio_pblkno) 622 break; 623 bq = bn; 624 } 625 TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue); 626 bioq->busy = 0; 627} 628 629
|