lkml.org 
[lkml]   [2021]   [Jul]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v5 5/6] block: add a helper to raise a media changed event
    Date
    From: Matteo Croce <mcroce@microsoft.com>

    Refactor disk_check_events() and move some code into disk_event_uevent().
    Then add disk_force_media_change(), a helper which will be used by
    devices to force issuing a DISK_EVENT_MEDIA_CHANGE event.

    Co-developed-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Matteo Croce <mcroce@microsoft.com>
    ---
    block/disk-events.c | 61 ++++++++++++++++++++++++++++++++-----------
    include/linux/genhd.h | 1 +
    2 files changed, 47 insertions(+), 15 deletions(-)

    diff --git a/block/disk-events.c b/block/disk-events.c
    index 04c52f3992ed..7445b8ff2775 100644
    --- a/block/disk-events.c
    +++ b/block/disk-events.c
    @@ -163,15 +163,31 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask)
    spin_unlock_irq(&ev->lock);
    }

    +/*
    + * Tell userland about new events. Only the events listed in @disk->events are
    + * reported, and only if DISK_EVENT_FLAG_UEVENT is set. Otherwise, events are
    + * processed internally but never get reported to userland.
    + */
    +static void disk_event_uevent(struct gendisk *disk, unsigned int events)
    +{
    + char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
    + int nr_events = 0, i;
    +
    + for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
    + if (events & disk->events & (1 << i))
    + envp[nr_events++] = disk_uevents[i];
    +
    + if (nr_events)
    + kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
    +}
    +
    static void disk_check_events(struct disk_events *ev,
    unsigned int *clearing_ptr)
    {
    struct gendisk *disk = ev->disk;
    - char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
    unsigned int clearing = *clearing_ptr;
    unsigned int events;
    unsigned long intv;
    - int nr_events = 0, i;

    /* check events */
    events = disk->fops->check_events(disk, clearing);
    @@ -193,19 +209,8 @@ static void disk_check_events(struct disk_events *ev,
    if (events & DISK_EVENT_MEDIA_CHANGE)
    inc_diskseq(disk);

    - /*
    - * Tell userland about new events. Only the events listed in
    - * @disk->events are reported, and only if DISK_EVENT_FLAG_UEVENT
    - * is set. Otherwise, events are processed internally but never
    - * get reported to userland.
    - */
    - for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
    - if ((events & disk->events & (1 << i)) &&
    - (disk->event_flags & DISK_EVENT_FLAG_UEVENT))
    - envp[nr_events++] = disk_uevents[i];
    -
    - if (nr_events)
    - kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
    + if (disk->event_flags & DISK_EVENT_FLAG_UEVENT)
    + disk_event_uevent(disk, events);
    }

    /**
    @@ -284,6 +289,32 @@ bool bdev_check_media_change(struct block_device *bdev)
    }
    EXPORT_SYMBOL(bdev_check_media_change);

    +/**
    + * disk_force_media_change - force a media change event
    + * @disk: the disk which will raise the event
    + * @events: the events to raise
    + *
    + * Generate uevents for the disk. If DISK_EVENT_MEDIA_CHANGE is present,
    + * attempt to free all dentries and inodes and invalidates all block
    + * device page cache entries in that case.
    + *
    + * Returns %true if DISK_EVENT_MEDIA_CHANGE was raised, or %false if not.
    + */
    +bool disk_force_media_change(struct gendisk *disk, unsigned int events)
    +{
    + disk_event_uevent(disk, events);
    +
    + if (!(events & DISK_EVENT_MEDIA_CHANGE))
    + return false;
    +
    + if (__invalidate_device(disk->part0, true))
    + pr_warn("VFS: busy inodes on changed media %s\n",
    + disk->disk_name);
    + set_bit(GD_NEED_PART_SCAN, &disk->state);
    + return true;
    +}
    +EXPORT_SYMBOL_GPL(disk_force_media_change);
    +
    /*
    * Separate this part out so that a different pointer for clearing_ptr can be
    * passed in for disk_clear_events.
    diff --git a/include/linux/genhd.h b/include/linux/genhd.h
    index 140c028845af..849486de81c6 100644
    --- a/include/linux/genhd.h
    +++ b/include/linux/genhd.h
    @@ -237,6 +237,7 @@ extern void disk_block_events(struct gendisk *disk);
    extern void disk_unblock_events(struct gendisk *disk);
    extern void disk_flush_events(struct gendisk *disk, unsigned int mask);
    bool set_capacity_and_notify(struct gendisk *disk, sector_t size);
    +bool disk_force_media_change(struct gendisk *disk, unsigned int events);

    /* drivers/char/random.c */
    extern void add_disk_randomness(struct gendisk *disk) __latent_entropy;
    --
    2.31.1
    \
     
     \ /
      Last update: 2021-07-13 01:09    [W:2.687 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site