/** * devt_from_partuuid - looks up the dev_t of a partition by its UUID * @uuid: min 36 byte char array containing a hex ascii UUID * * The function will return the first partition which contains a matching * UUID value in its partition_meta_info struct. This does not search * by filesystem UUIDs. * * If @uuid is followed by a "/PARTNROFF=%d", then the number will be * extracted and used as an offset from the partition identified by the UUID. * * Returns the matching dev_t on success or 0 on failure. */ static dev_t devt_from_partuuid(char *uuid_str) { dev_t res = 0; struct device *dev = NULL; u8 uuid[16]; struct gendisk *disk; struct hd_struct *part; int offset = 0; if (strlen(uuid_str) < 36) goto done; /* Check for optional partition number offset attributes. */ if (uuid_str[36]) { char c = 0; /* Explicitly fail on poor PARTUUID syntax. */ if (sscanf(&uuid_str[36], "/PARTNROFF=%d%c", &offset, &c) != 1) { printk(KERN_ERR "VFS: PARTUUID= is invalid.\n" "Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]\n"); if (root_wait) printk(KERN_ERR "Disabling rootwait; root= is invalid.\n"); root_wait = 0; goto done; } } /* Pack the requested UUID in the expected format. */ part_pack_uuid(uuid_str, uuid); dev = class_find_device(&block_class, NULL, uuid, &match_dev_by_uuid); if (!dev) goto done; res = dev->devt; /* Attempt to find the partition by offset. */ if (!offset) goto no_offset; res = 0; disk = part_to_disk(dev_to_part(dev)); part = disk_get_part(disk, dev_to_part(dev)->partno + offset); if (part) { res = part_devt(part); put_device(part_to_dev(part)); } no_offset: put_device(dev); done: return res; }
/** * devt_from_partuuid - looks up the dev_t of a partition by its UUID * @uuid: char array containing ascii UUID * * The function will return the first partition which contains a matching * UUID value in its partition_meta_info struct. This does not search * by filesystem UUIDs. * * If @uuid is followed by a "/PARTNROFF=%d", then the number will be * extracted and used as an offset from the partition identified by the UUID. * * Returns the matching dev_t on success or 0 on failure. */ static dev_t devt_from_partuuid(const char *uuid_str) { dev_t res = 0; struct uuidcmp cmp; struct device *dev = NULL; struct gendisk *disk; struct hd_struct *part; int offset = 0; bool clear_root_wait = false; char *slash; cmp.uuid = uuid_str; slash = strchr(uuid_str, '/'); /* Check for optional partition number offset attributes. */ if (slash) { char c = 0; /* Explicitly fail on poor PARTUUID syntax. */ if (sscanf(slash + 1, "PARTNROFF=%d%c", &offset, &c) != 1) { clear_root_wait = true; goto done; } cmp.len = slash - uuid_str; } else { cmp.len = strlen(uuid_str); } if (!cmp.len) { clear_root_wait = true; goto done; } dev = class_find_device(&block_class, NULL, &cmp, &match_dev_by_uuid); if (!dev) goto done; res = dev->devt; /* Attempt to find the partition by offset. */ if (!offset) goto no_offset; res = 0; disk = part_to_disk(dev_to_part(dev)); part = disk_get_part(disk, dev_to_part(dev)->partno + offset); if (part) { res = part_devt(part); put_device(part_to_dev(part)); } no_offset: put_device(dev); done: if (clear_root_wait) { pr_err("VFS: PARTUUID= is invalid.\n" "Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]\n"); if (root_wait) pr_err("Disabling rootwait; root= is invalid.\n"); root_wait = 0; } return res; }
static int blk_trace_synthesize_old_trace(struct trace_iterator *iter) { struct trace_seq *s = &iter->seq; struct blk_io_trace *t = (struct blk_io_trace *)iter->ent; const int offset = offsetof(struct blk_io_trace, sector); struct blk_io_trace old = { .magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION, .time = iter->ts, }; if (!trace_seq_putmem(s, &old, offset)) return 0; return trace_seq_putmem(s, &t->sector, sizeof(old) - offset + t->pdu_len); } static enum print_line_t blk_trace_event_print_binary(struct trace_iterator *iter, int flags) { return blk_trace_synthesize_old_trace(iter) ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; } static enum print_line_t blk_tracer_print_line(struct trace_iterator *iter) { if (!(blk_tracer_flags.val & TRACE_BLK_OPT_CLASSIC)) return TRACE_TYPE_UNHANDLED; return print_one_line(iter, true); } static int blk_tracer_set_flag(u32 old_flags, u32 bit, int set) { /* don't output context-info for blk_classic output */ if (bit == TRACE_BLK_OPT_CLASSIC) { if (set) trace_flags &= ~TRACE_ITER_CONTEXT_INFO; else trace_flags |= TRACE_ITER_CONTEXT_INFO; } return 0; } static struct tracer blk_tracer __read_mostly = { .name = "blk", .init = blk_tracer_init, .reset = blk_tracer_reset, .start = blk_tracer_start, .stop = blk_tracer_stop, .print_header = blk_tracer_print_header, .print_line = blk_tracer_print_line, .flags = &blk_tracer_flags, .set_flag = blk_tracer_set_flag, }; static struct trace_event trace_blk_event = { .type = TRACE_BLK, .trace = blk_trace_event_print, .binary = blk_trace_event_print_binary, }; static int __init init_blk_tracer(void) { if (!register_ftrace_event(&trace_blk_event)) { pr_warning("Warning: could not register block events\n"); return 1; } if (register_tracer(&blk_tracer) != 0) { pr_warning("Warning: could not register the block tracer\n"); unregister_ftrace_event(&trace_blk_event); return 1; } return 0; } device_initcall(init_blk_tracer); static int blk_trace_remove_queue(struct request_queue *q) { struct blk_trace *bt; bt = xchg(&q->blk_trace, NULL); if (bt == NULL) return -EINVAL; if (atomic_dec_and_test(&blk_probes_ref)) blk_unregister_tracepoints(); blk_trace_free(bt); return 0; } /* * Setup everything required to start tracing */ static int blk_trace_setup_queue(struct request_queue *q, struct block_device *bdev) { struct blk_trace *old_bt, *bt = NULL; int ret = -ENOMEM; bt = kzalloc(sizeof(*bt), GFP_KERNEL); if (!bt) return -ENOMEM; bt->msg_data = __alloc_percpu(BLK_TN_MAX_MSG, __alignof__(char)); if (!bt->msg_data) goto free_bt; bt->dev = bdev->bd_dev; bt->act_mask = (u16)-1; blk_trace_setup_lba(bt, bdev); old_bt = xchg(&q->blk_trace, bt); if (old_bt != NULL) { (void)xchg(&q->blk_trace, old_bt); ret = -EBUSY; goto free_bt; } if (atomic_inc_return(&blk_probes_ref) == 1) blk_register_tracepoints(); return 0; free_bt: blk_trace_free(bt); return ret; } /* * sysfs interface to enable and configure tracing */ static ssize_t sysfs_blk_trace_attr_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t sysfs_blk_trace_attr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); #define BLK_TRACE_DEVICE_ATTR(_name) \ DEVICE_ATTR(_name, S_IRUGO | S_IWUSR, \ sysfs_blk_trace_attr_show, \ sysfs_blk_trace_attr_store) static BLK_TRACE_DEVICE_ATTR(enable); static BLK_TRACE_DEVICE_ATTR(act_mask); static BLK_TRACE_DEVICE_ATTR(pid); static BLK_TRACE_DEVICE_ATTR(start_lba); static BLK_TRACE_DEVICE_ATTR(end_lba); static struct attribute *blk_trace_attrs[] = { &dev_attr_enable.attr, &dev_attr_act_mask.attr, &dev_attr_pid.attr, &dev_attr_start_lba.attr, &dev_attr_end_lba.attr, NULL }; struct attribute_group blk_trace_attr_group = { .name = "trace", .attrs = blk_trace_attrs, }; static const struct { int mask; const char *str; } mask_maps[] = { { BLK_TC_READ, "read" }, { BLK_TC_WRITE, "write" }, { BLK_TC_FLUSH, "flush" }, { BLK_TC_SYNC, "sync" }, { BLK_TC_QUEUE, "queue" }, { BLK_TC_REQUEUE, "requeue" }, { BLK_TC_ISSUE, "issue" }, { BLK_TC_COMPLETE, "complete" }, { BLK_TC_FS, "fs" }, { BLK_TC_PC, "pc" }, { BLK_TC_AHEAD, "ahead" }, { BLK_TC_META, "meta" }, { BLK_TC_DISCARD, "discard" }, { BLK_TC_DRV_DATA, "drv_data" }, { BLK_TC_FUA, "fua" }, }; static int blk_trace_str2mask(const char *str) { int i; int mask = 0; char *buf, *s, *token; buf = kstrdup(str, GFP_KERNEL); if (buf == NULL) return -ENOMEM; s = strstrip(buf); while (1) { token = strsep(&s, ","); if (token == NULL) break; if (*token == '\0') continue; for (i = 0; i < ARRAY_SIZE(mask_maps); i++) { if (strcasecmp(token, mask_maps[i].str) == 0) { mask |= mask_maps[i].mask; break; } } if (i == ARRAY_SIZE(mask_maps)) { mask = -EINVAL; break; } } kfree(buf); return mask; } static ssize_t blk_trace_mask2str(char *buf, int mask) { int i; char *p = buf; for (i = 0; i < ARRAY_SIZE(mask_maps); i++) { if (mask & mask_maps[i].mask) { p += sprintf(p, "%s%s", (p == buf) ? "" : ",", mask_maps[i].str); } } *p++ = '\n'; return p - buf; } static struct request_queue *blk_trace_get_queue(struct block_device *bdev) { if (bdev->bd_disk == NULL) return NULL; return bdev_get_queue(bdev); } static ssize_t sysfs_blk_trace_attr_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hd_struct *p = dev_to_part(dev); struct request_queue *q; struct block_device *bdev; ssize_t ret = -ENXIO; lock_kernel(); bdev = bdget(part_devt(p)); if (bdev == NULL) goto out_unlock_kernel; q = blk_trace_get_queue(bdev); if (q == NULL) goto out_bdput; mutex_lock(&bdev->bd_mutex); if (attr == &dev_attr_enable) { ret = sprintf(buf, "%u\n", !!q->blk_trace); goto out_unlock_bdev; } if (q->blk_trace == NULL) ret = sprintf(buf, "disabled\n"); else if (attr == &dev_attr_act_mask) ret = blk_trace_mask2str(buf, q->blk_trace->act_mask); else if (attr == &dev_attr_pid) ret = sprintf(buf, "%u\n", q->blk_trace->pid); else if (attr == &dev_attr_start_lba) ret = sprintf(buf, "%llu\n", q->blk_trace->start_lba); else if (attr == &dev_attr_end_lba) ret = sprintf(buf, "%llu\n", q->blk_trace->end_lba); out_unlock_bdev: mutex_unlock(&bdev->bd_mutex); out_bdput: bdput(bdev); out_unlock_kernel: unlock_kernel(); return ret; } static ssize_t sysfs_blk_trace_attr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct block_device *bdev; struct request_queue *q; struct hd_struct *p; u64 value; ssize_t ret = -EINVAL; if (count == 0) goto out; if (attr == &dev_attr_act_mask) { if (sscanf(buf, "%llx", &value) != 1) { /* Assume it is a list of trace category names */ ret = blk_trace_str2mask(buf); if (ret < 0) goto out; value = ret; } } else if (sscanf(buf, "%llu", &value) != 1) goto out; ret = -ENXIO; lock_kernel(); p = dev_to_part(dev); bdev = bdget(part_devt(p)); if (bdev == NULL) goto out_unlock_kernel; q = blk_trace_get_queue(bdev); if (q == NULL) goto out_bdput; mutex_lock(&bdev->bd_mutex); if (attr == &dev_attr_enable) { if (value) ret = blk_trace_setup_queue(q, bdev); else ret = blk_trace_remove_queue(q); goto out_unlock_bdev; } ret = 0; if (q->blk_trace == NULL) ret = blk_trace_setup_queue(q, bdev); if (ret == 0) { if (attr == &dev_attr_act_mask) q->blk_trace->act_mask = value; else if (attr == &dev_attr_pid) q->blk_trace->pid = value; else if (attr == &dev_attr_start_lba) q->blk_trace->start_lba = value; else if (attr == &dev_attr_end_lba) q->blk_trace->end_lba = value; } out_unlock_bdev: mutex_unlock(&bdev->bd_mutex); out_bdput: bdput(bdev); out_unlock_kernel: unlock_kernel(); out: return ret ? ret : count; } int blk_trace_init_sysfs(struct device *dev) { return sysfs_create_group(&dev->kobj, &blk_trace_attr_group); } void blk_trace_remove_sysfs(struct device *dev) { sysfs_remove_group(&dev->kobj, &blk_trace_attr_group); }
void show_gend(void) { struct class_dev_iter iter; struct device *dev; class_dev_iter_init(&iter, my_block_class, NULL, my_disk_type); // struct class_dev_iter { // [0] struct klist_iter ki; // [16] const struct device_type *type; //} //printk("iter %p iter.ki %p i_klist %p i_cur %p\n", // &iter, iter.ki, iter.ki.i_klist, iter.ki.i_cur); while ((dev = my_class_dev_iter_next(&iter))) { struct gendisk *disk = dev_to_disk(dev); struct disk_part_iter piter; struct hd_struct *part; char name_buf[BDEVNAME_SIZE]; char devt_buf[BDEVT_SIZE]; char uuid_buf[PARTITION_META_INFO_UUIDLTH * 2 + 5]; // printk("gen %p name %s\n", disk, disk->disk_name); /* * Don't show empty devices or things that have been * suppressed */ if (get_capacity(disk) == 0 || (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) continue; // James: we only want to verify 'sda' if (strcmp(disk->disk_name, "sda") != 0) continue; /* * Note, unlike /proc/partitions, I am showing the * numbers in hex - the same format as the root= * option takes. */ disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); printk("gen %p name %s\n disk_part_tbl %p ", disk, disk->disk_name, disk->part_tbl); while ((part = disk_part_iter_next(&piter))) { bool is_part0 = part == &disk->part0; printk("part %p\n", part); uuid_buf[0] = '\0'; if (part->info) snprintf(uuid_buf, sizeof(uuid_buf), "%pU", part->info->uuid); printk("%s%s %10llu %s %s", is_part0 ? "" : " ", bdevt_str(part_devt(part), devt_buf), (unsigned long long)part->nr_sects >> 1, disk_name(disk, part->partno, name_buf), uuid_buf); if (is_part0) { if (disk->driverfs_dev != NULL && disk->driverfs_dev->driver != NULL) printk(" driver: %s\n", disk->driverfs_dev->driver->name); else printk(" (driver?)\n"); } else printk("\n"); } disk_part_iter_exit(&piter); } class_dev_iter_exit(&iter); }