Skip to content

Commit e6138dc

Browse files
teknoraveraxboe
authored andcommitted
block: add a helper to raise a media changed event
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 <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Signed-off-by: Matteo Croce <[email protected]> Tested-by: Luca Boccassi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 13927b3 commit e6138dc

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

block/disk-events.c

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,31 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask)
163163
spin_unlock_irq(&ev->lock);
164164
}
165165

166+
/*
167+
* Tell userland about new events. Only the events listed in @disk->events are
168+
* reported, and only if DISK_EVENT_FLAG_UEVENT is set. Otherwise, events are
169+
* processed internally but never get reported to userland.
170+
*/
171+
static void disk_event_uevent(struct gendisk *disk, unsigned int events)
172+
{
173+
char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
174+
int nr_events = 0, i;
175+
176+
for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
177+
if (events & disk->events & (1 << i))
178+
envp[nr_events++] = disk_uevents[i];
179+
180+
if (nr_events)
181+
kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
182+
}
183+
166184
static void disk_check_events(struct disk_events *ev,
167185
unsigned int *clearing_ptr)
168186
{
169187
struct gendisk *disk = ev->disk;
170-
char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
171188
unsigned int clearing = *clearing_ptr;
172189
unsigned int events;
173190
unsigned long intv;
174-
int nr_events = 0, i;
175191

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

196-
/*
197-
* Tell userland about new events. Only the events listed in
198-
* @disk->events are reported, and only if DISK_EVENT_FLAG_UEVENT
199-
* is set. Otherwise, events are processed internally but never
200-
* get reported to userland.
201-
*/
202-
for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
203-
if ((events & disk->events & (1 << i)) &&
204-
(disk->event_flags & DISK_EVENT_FLAG_UEVENT))
205-
envp[nr_events++] = disk_uevents[i];
206-
207-
if (nr_events)
208-
kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
212+
if (disk->event_flags & DISK_EVENT_FLAG_UEVENT)
213+
disk_event_uevent(disk, events);
209214
}
210215

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

292+
/**
293+
* disk_force_media_change - force a media change event
294+
* @disk: the disk which will raise the event
295+
* @events: the events to raise
296+
*
297+
* Generate uevents for the disk. If DISK_EVENT_MEDIA_CHANGE is present,
298+
* attempt to free all dentries and inodes and invalidates all block
299+
* device page cache entries in that case.
300+
*
301+
* Returns %true if DISK_EVENT_MEDIA_CHANGE was raised, or %false if not.
302+
*/
303+
bool disk_force_media_change(struct gendisk *disk, unsigned int events)
304+
{
305+
disk_event_uevent(disk, events);
306+
307+
if (!(events & DISK_EVENT_MEDIA_CHANGE))
308+
return false;
309+
310+
if (__invalidate_device(disk->part0, true))
311+
pr_warn("VFS: busy inodes on changed media %s\n",
312+
disk->disk_name);
313+
set_bit(GD_NEED_PART_SCAN, &disk->state);
314+
return true;
315+
}
316+
EXPORT_SYMBOL_GPL(disk_force_media_change);
317+
287318
/*
288319
* Separate this part out so that a different pointer for clearing_ptr can be
289320
* passed in for disk_clear_events.

include/linux/genhd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ extern void disk_block_events(struct gendisk *disk);
237237
extern void disk_unblock_events(struct gendisk *disk);
238238
extern void disk_flush_events(struct gendisk *disk, unsigned int mask);
239239
bool set_capacity_and_notify(struct gendisk *disk, sector_t size);
240+
bool disk_force_media_change(struct gendisk *disk, unsigned int events);
240241

241242
/* drivers/char/random.c */
242243
extern void add_disk_randomness(struct gendisk *disk) __latent_entropy;

0 commit comments

Comments
 (0)