Re: [PATCH v3 8/8] block: Assign a lock_class per gendisk used for wait_for_completion()

Byungchul Park
2017-10-25T00:26:27Z

On Tue, Oct 24, 2017 at 12:15:51PM +0200, Ingo Molnar wrote:
> > @@ -1409,9 +1403,12 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
> > disk_to_dev(disk)->type = &disk_type;
> > device_initialize(disk_to_dev(disk));
> > }
> > +
> > + lockdep_init_map(&disk->lockdep_map, lock_name, key, 0);
>
> lockdep_init_map() depends on CONFIG_DEBUG_LOCK_ALLOC IIRC, but the data structure
> change you made depends on CONFIG_LOCKDEP_COMPLETIONS:

OMG, my mistake! I am very sorry. I will fix it.

BTW, lockdep_init_map() seems to decide whether using lockdep_map or
ignoring it, depending on CONFIG_LOCKDEP than CONFIG_DEBUG_LOCK_ALLOC.

> > return disk;
> > }
> > -EXPORT_SYMBOL(alloc_disk_node);
> > +EXPORT_SYMBOL(__alloc_disk_node);
> >
> > struct kobject *get_disk(struct gendisk *disk)
> > {
> > diff --git a/include/linux/genhd.h b/include/linux/genhd.h
> > index 6d85a75..9832e3c 100644
> > --- a/include/linux/genhd.h
> > +++ b/include/linux/genhd.h
> > @@ -206,6 +206,9 @@ struct gendisk {
> > #endif /* CONFIG_BLK_DEV_INTEGRITY */
> > int node_id;
> > struct badblocks *bb;
> > +#ifdef CONFIG_LOCKDEP_COMPLETIONS
> > + struct lockdep_map lockdep_map;
> > +#endif
> > };
>
> Which is risking a future build failure at minimum.
>
> Isn't lockdep_map a zero size structure that is always defined? If yes then
> there's no need for an #ifdef.

No, a zero size structure for lockdep_map is not provided yet.
There are two options I can do:

1. Add a zero size structure for lockdep_map and remove #ifdef
2. Replace CONFIG_LOCKDEP_COMPLETIONS with CONFIG_LOCKDEP here.

Or something else?

Which one do you prefer?

> Also:
>
> >
> > static inline struct gendisk *part_to_disk(struct hd_struct *part)
> > @@ -590,8 +593,7 @@ extern struct hd_struct * __must_check add_partition(struct gendisk *disk,
> > extern void delete_partition(struct gendisk *, int);
> > extern void printk_all_partitions(void);
> >
> > -extern struct gendisk *alloc_disk_node(int minors, int node_id);
> > -extern struct gendisk *alloc_disk(int minors);
> > +extern struct gendisk *__alloc_disk_node(int minors, int node_id, struct lock_class_key *key, const char *lock_name);
> > extern struct kobject *get_disk(struct gendisk *disk);
> > extern void put_disk(struct gendisk *disk);
> > extern void blk_register_region(dev_t devt, unsigned long range,
> > @@ -615,6 +617,22 @@ extern ssize_t part_fail_store(struct device *dev,
> > const char *buf, size_t count);
> > #endif /* CONFIG_FAIL_MAKE_REQUEST */
> >
> > +#ifdef CONFIG_LOCKDEP_COMPLETIONS
> > +#define alloc_disk_node(m, id) \
> > +({ \
> > + static struct lock_class_key __key; \
> > + const char *__lock_name; \
> > + \
> > + __lock_name = "(complete)"#m"("#id")"; \
> > + \
> > + __alloc_disk_node(m, id, &__key, __lock_name); \
> > +})
> > +#else
> > +#define alloc_disk_node(m, id) __alloc_disk_node(m, id, NULL, NULL)
> > +#endif
> > +
> > +#define alloc_disk(m) alloc_disk_node(m, NUMA_NO_NODE)
> > +
> > static inline int hd_ref_init(struct hd_struct *part)
> > {
> > if (percpu_ref_init(&part->ref, __delete_partition, 0,
>
> Why is the lockdep_map passed in to the init function? Since it's wrapped in an
> ugly fashion anyway, why not introduce a clean inline function that calls

This is the way workqueue adopted for that purpose. BTW, can I make
a lock_class_key distinguishable from another of a different gendisk,
using inline function?

> lockdep_init_map() on the returned structure.

Ok. I will make it work on the returned structre instead of passing it.

> No #ifdefs required, and no uglification of the alloc_disk_node() interface.

Ok. I will remove this #ifdef.

Thank you very much.