Skip to content

Commit

Permalink
Rewrite check_disk_change cleanly
Browse files Browse the repository at this point in the history
  • Loading branch information
ghaerr committed Oct 5, 2023
1 parent 8674fbc commit 80e582a
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 48 deletions.
1 change: 1 addition & 0 deletions elks/arch/i86/drivers/block/blk.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ static void end_request(int uptodate)
req = CURRENT;

if (!uptodate) {
/*if (req->rq_errors >= 0)*/
printk(DEVICE_NAME ": I/O %s error dev %D lba sector %lu\n",
(req->rq_cmd == WRITE)? "write": "read",
req->rq_dev, req->rq_sector);
Expand Down
101 changes: 61 additions & 40 deletions elks/arch/i86/drivers/block/directfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
#include <linuxmt/config.h>
#include <linuxmt/sched.h>
#include <linuxmt/fs.h>
#include <linuxmt/stat.h>
#include <linuxmt/kernel.h>
#include <linuxmt/timer.h>
#include <linuxmt/mm.h>
Expand Down Expand Up @@ -256,6 +257,9 @@ static int access_count;
static int fdc_busy;
static struct wait_queue fdc_wait;

/* bit vector set when media changed - causes I/O to be discarded until unset */
static unsigned int changed_floppies;

/*
* Threshold for reporting FDC errors to the console.
* Setting this to zero may flood your screen when using
Expand Down Expand Up @@ -300,6 +304,7 @@ static void floppy_shutdown(void);
static void motor_off_callback(int);
static int DFPROC floppy_register(void);
static void DFPROC floppy_deregister(void);
static void floppy_release(struct inode *inode, struct file *filp);

static void DFPROC delay_loop(int cnt)
{
Expand Down Expand Up @@ -942,7 +947,6 @@ static void floppy_shutdown(void)
DEBUG("[%u]shtdwn0x%x|%x-", (unsigned int)jiffies, current_DOR, running);
do_floppy = NULL;
printk("df%d: FDC cmd timeout\n", current_drive);
request_done(0);
recover = 1;
reset_floppy();
redo_fd_request();
Expand Down Expand Up @@ -1003,86 +1007,92 @@ static void shake_one(void)
* This routine checks whether a removable media has been changed,
* and invalidates all inode and buffer-cache-entries in that case.
* It is called from device open, mount and file read/write code.
* Because the FDC is interrupt driven and can't sleep, this routine
* must be called by a non-interrupt routine, as invalidate_buffers
* may sleep, and otherwise all accessed kernel variables would need
* protection via interrupt disabling.
*
* Since this driver is the only driver implementing media change,
* the entire routine has been moved here for simplicity.
*/
static unsigned int changed_floppies;

#if DEBUG_EVENT
static int debug_changed;
void fake_disk_change(void)
{
printk("X");
debug("X");
debug_changed = 1;
}
#endif

int check_disk_change(kdev_t dev)
{
int drive;
unsigned int mask;
struct super_block *s;
struct inode *inodep;

debug_setcallback(2, fake_disk_change);
if (MAJOR(dev) != MAJOR_NR)
return 0;
printk("C%d", dev&3);
drive = DEVICE_NR(dev);
mask = 1 << drive;
if (!dev && changed_floppies) {
dev = (changed_floppies & 1)? MKDEV(MAJOR_NR, 0): MKDEV(MAJOR_NR, 1);
} else {
if (MAJOR(dev) != MAJOR_NR)
return 0;
}
debug("C%d", dev&3);
mask = 1 << DEVICE_NR(dev);
if (!(changed_floppies & mask)) {
printk("N");
debug("N");
return 0;
}
printk("Y");
changed_floppies &= ~mask;
debug_changed = 0;
debug("Y");

printk("VFS: Disk change detected on dev %D\n", dev);
if (dev == ROOT_DEV) panic("Root media changed");

/* Can't call put_super since media changed, just clear and unmount for now */
for (s = super_blocks; s < &super_blocks[NR_SUPER]; s++) {
if (s->s_dev == dev) {
printk("Clearing super block on %D\n", dev);
if (s->s_mounted) {
printk("VFS: '%s' force unmounted\n", s->s_mntonname);
//iput(s->s_mounted);
s->s_mounted = NULL;
//s->s_covered->i_mount = NULL;
//iput(s->s_covered);
s->s_covered = NULL;
}
s->s_dev = 0;
}
/* I/O is ignored but inuse, locked, or dirty inodes may not be cleared... */
s = get_super(dev);
if (s && s->s_mounted) {
do_umount(dev);
printk("VFS: Unmounting %s, media changed\n", s->s_mntonname);
/* fake up inode to enable device release */
inodep = new_inode(NULL, S_IFBLK);
inodep->i_rdev = dev;
floppy_release(inodep, NULL);
iput(inodep);
}

/* inuse, locked, or dirty inodes aren't cleared... */
fsync_dev(dev);
invalidate_inodes(dev);
invalidate_buffers(dev);

if (drive == buffer_drive)
buffer_track = -1;
recalibrate = 1;
changed_floppies &= ~mask;
debug_changed = 0;
//recalibrate = 1;
printk("VFS: Disk media change completed on dev %D\n", dev);

return 1;
}
#endif /* CHECK_DISK_CHANGE */

static void DFPROC floppy_ready(void)
{
DEBUG("RDY0x%x,%d,%d-", inb(FD_DIR), reset, recalibrate);
DEBUG("RDY%d,%d-", reset, recalibrate);

#if CHECK_DISK_CHANGE
/* check if disk changed since last cmd (PC/AT+) */
if ((debug_changed && current_drive == 1)
if (0
#if DEBUG_EVENT
|| (debug_changed && current_drive == 1)
#endif
#if CHECK_DIR_REG
|| (fdc_version >= FDC_TYPE_8272PC_AT && (inb(FD_DIR) & 0x80))
#endif
) {
/* this will discard any queued I/O immediately */
changed_floppies |= 1 << current_drive;

printk("df%d: Disk type undefined after disk change\n", current_drive);
printk("df%d: Disk media change detected, suspending I/O\n", current_drive);
current_type[current_drive] = NULL; /* comment out to keep last media format */

if (current_drive == buffer_drive)
buffer_track = -1;

#if CHECK_DIR_REG
if (!reset && !recalibrate) {
if (current_track && current_track != NO_TRACK)
Expand All @@ -1094,6 +1104,8 @@ static void DFPROC floppy_ready(void)
return;
}
#endif
redo_fd_request();
return;
}
#endif /* CHECK_DISK_CHANGE */

Expand Down Expand Up @@ -1129,6 +1141,15 @@ static void DFPROC redo_fd_request(void)
seek = 0;
type = MINOR(req->rq_dev) >> MINOR_SHIFT;
drive = DEVICE_NR(req->rq_dev);

#if CHECK_DISK_CHANGE
if (changed_floppies & (1 << drive)) {
req->rq_errors = -1; /* stop error display */
request_done(0);
goto repeat;
}
#endif

if (type > 3)
floppy = &minor_types[type >> 2];
else { /* Auto-detection */
Expand Down Expand Up @@ -1361,6 +1382,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
drive = DEVICE_NR(inode->i_rdev);

#if CHECK_DISK_CHANGE
debug_setcallback(2, fake_disk_change); /* debug trigger ^P */
if (filp && filp->f_mode) {
if (check_disk_change(inode->i_rdev))
return -ENXIO;
Expand Down Expand Up @@ -1390,8 +1412,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
fd_ref[drive]++;
inode->i_size = (sector_t)floppy->size << 9; /* NOTE: assumes sector size 512 */
open_inode = inode;
DEBUG("df%d: open dv %x, sz %lu, %s\n", drive, inode->i_rdev, inode->i_size,
floppy->name);
DEBUG("df%d: open %s, size %lu\n", drive, floppy->name, inode->i_size);

return 0;
}
Expand Down
1 change: 1 addition & 0 deletions elks/arch/i86/drivers/char/ntty.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ int tty_intcheck(register struct tty *ttyp, unsigned char key)
kill_pg(ttyp->pgrp, sig, 1);
}
}
(void) check_disk_change(0); /* check any floppy media changed */
return sig;
}

Expand Down
6 changes: 6 additions & 0 deletions elks/fs/block_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ size_t block_read(struct inode *inode, struct file *filp, char *buf, size_t coun
if (pos <= 0)
return 0; /* EOF */

if (check_disk_change(inode->i_rdev))
return -ENXIO;

if ((loff_t)count > pos) count = (size_t)pos;

while (count > 0) {
Expand Down Expand Up @@ -70,6 +73,9 @@ size_t block_write(struct inode *inode, struct file *filp, char *buf, size_t cou
size_t chars, offset;
size_t written = 0;

if (check_disk_change(inode->i_rdev))
return -ENXIO;

if (filp->f_flags & O_APPEND) filp->f_pos = (loff_t)inode->i_size;

while (count > 0) {
Expand Down
2 changes: 1 addition & 1 deletion elks/fs/minix/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct buffer_head *get_map_block(kdev_t dev, block_t block)
else
bh = bread(dev, block);
if (!EBH(bh)->b_uptodate) {
printk("get_map_block: can't read block %D/%u\n", dev, block);
debug_blk("get_map_block: can't read block %D/%u\n", dev, block);
brelse(bh);
return NULL;
}
Expand Down
12 changes: 5 additions & 7 deletions elks/fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ void sync_supers(kdev_t dev)
} while (++sb < super_blocks + NR_SUPER);
}

static struct super_block *get_super(kdev_t dev)
struct super_block *get_super(kdev_t dev)
{
register struct super_block *s;

Expand Down Expand Up @@ -170,7 +170,7 @@ static struct super_block *read_super(kdev_t dev, int t, int flags,
register struct file_system_type *type;

if (!dev) return NULL;
check_disk_change(dev);
(void) check_disk_change(dev);
s = get_super(dev);
if (s) return s;

Expand Down Expand Up @@ -208,7 +208,7 @@ static struct super_block *read_super(kdev_t dev, int t, int flags,
return s;
}

static int do_umount(kdev_t dev)
int do_umount(kdev_t dev)
{
register struct super_block *sb;
register struct super_operations *sop;
Expand Down Expand Up @@ -489,10 +489,8 @@ void mount_root(void)
}
} while (*(++fs_type) && !retval);

#ifdef CONFIG_BLK_DEV_BIOS
if (ROOT_DEV == DEV_FD0) {
if (!filp->f_op->release)
printk("Release not defined\n");
#if defined(CONFIG_BLK_DEV_BFD) || defined(CONFIG_BLK_DEV_FD)
if (ROOT_DEV == DEV_FD0 || ROOT_DEV == DEV_DF0) {
close_filp(d_inode, filp);
printk("VFS: Insert root floppy and press ENTER\n");
wait_for_keypress();
Expand Down
2 changes: 2 additions & 0 deletions elks/include/linuxmt/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,9 @@ extern struct buffer_head *readbuf(struct buffer_head *);
extern void ll_rw_blk(int,struct buffer_head *);
extern int get_sector_size(kdev_t dev);

extern struct super_block *get_super(kdev_t);
extern void put_super(kdev_t);
extern int do_umount(kdev_t);
extern kdev_t ROOT_DEV;

extern void mount_root(void);
Expand Down

0 comments on commit 80e582a

Please sign in to comment.