more info to bug report, Kernel (2.2.9) crash after trying tomount a swap-device.

Manfred Spraul (manfreds@colorfullife.com)
Sat, 5 Jun 1999 22:08:15 +0200


This is a multi-part message in MIME format.

------=_NextPart_000_001C_01BEAF9F.E8D9EED0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

I think you ran into the same problem I had a few weeks ago:
I typed
#swapon /dev/hda1
instead of
#swapon /dev/hda3
and the computer hung.
The problem:
the kernel prevents you from mounting a filesystem twice, and
it prevents you from mouting a swap partition twice,
but if you call sys_swapon() on a filesystem, the this crashes:
(try "swapon /dev/<root>", [fsck...])
- sys_swapon() must set the block size, otherwise it
can't check the superblock
- settings the blocksize prevents the filesystem from
accessing the device
--> crash.

I've written and posted a patch, but I received no replies.
I've attached the patch, but I tested it only with 2.2.6.

--
    Manfred

------=_NextPart_000_001C_01BEAF9F.E8D9EED0 Content-Type: application/octet-stream; name="patch_busy-2.2.6" Content-Disposition: attachment; filename="patch_busy-2.2.6" Content-Transfer-Encoding: quoted-printable

// $Header: /pub/cvs/ms/patches/patch_busy-2.2.6,v 1.1 1999/05/26 = 15:21:45 ms Exp $ diff -r -u -P -x CVS -x *,v 2.2.6/drivers/block/ll_rw_blk.c = current/drivers/block/ll_rw_blk.c --- 2.2.6/drivers/block/ll_rw_blk.c Wed Mar 31 00:56:57 1999 +++ current/drivers/block/ll_rw_blk.c Thu Apr 22 18:02:20 1999 @@ -16,6 +16,7 @@ #include <linux/config.h> #include <linux/locks.h> #include <linux/mm.h> +#include <linux/slab.h> #include <linux/init.h> =20 #include <asm/system.h> @@ -241,8 +242,24 @@ } =20 /* RO fail safe mechanism */ +/* device busy: (C) Manfred Spraul masp0008@stud.uni-sb.de */ =20 -static long ro_bits[MAX_BLKDEV][8]; +struct kdev_bits { + unsigned char ro_bits[(1U << MINORBITS)/8]; + unsigned char busy_bits[(1U << MINORBITS)/8]; +}; + +static struct kdev_bits* kdev_info[MAX_BLKDEV] =3D { NULL, NULL }; + +#define ALLOC_KDEV_BITS(major) \ + if (kdev_info[major] =3D=3D NULL) { \ + kdev_info[major] =3D kmalloc(sizeof(struct kdev_bits),GFP_KERNEL); \ + if(kdev_info[major] =3D=3D NULL) { \ + printk("ALLOC_KDEV_BITS() failed due to ENOMEM.\n"); \ + return; \ + } \ + memset(kdev_info[major],0,sizeof(struct kdev_bits)); \ + } =20 int is_read_only(kdev_t dev) { @@ -251,7 +268,8 @@ major =3D MAJOR(dev); minor =3D MINOR(dev); if (major < 0 || major >=3D MAX_BLKDEV) return 0; - return ro_bits[major][minor >> 5] & (1 << (minor & 31)); + if (kdev_info[major] =3D=3D NULL) return 0; + return kdev_info[major]->ro_bits[minor >> 3] & (1 << (minor & = 7)); } =20 void set_device_ro(kdev_t dev,int flag) @@ -261,10 +279,39 @@ major =3D MAJOR(dev); minor =3D MINOR(dev); if (major < 0 || major >=3D MAX_BLKDEV) return; - if (flag) ro_bits[major][minor >> 5] |=3D 1 << (minor & 31); - else ro_bits[major][minor >> 5] &=3D ~(1 << (minor & 31)); + ALLOC_KDEV_BITS(major) + if (flag) + kdev_info[major]->ro_bits[minor >> 3] |=3D 1 << (minor & 7); + else + kdev_info[major]->ro_bits[minor >> 3] &=3D ~(1 << (minor & 7)); +} + +int is_device_busy(kdev_t dev) +{ + int minor,major; + + major =3D MAJOR(dev); + minor =3D MINOR(dev); + if (major < 0 || major >=3D MAX_BLKDEV) return 0; + if (kdev_info[major] =3D=3D NULL) return 0; + return kdev_info[major]->busy_bits[minor >> 3] & (1 << (minor & 7)); } =20 +void set_device_busy(kdev_t dev,int flag) +{ + int minor,major; +=09 + major =3D MAJOR(dev); + minor =3D MINOR(dev); + if (major < 0 || major >=3D MAX_BLKDEV) return; + ALLOC_KDEV_BITS(major) + if (flag) + kdev_info[major]->busy_bits[minor >> 3] |=3D 1 << (minor & 7); + else + kdev_info[major]->busy_bits[minor >> 3] &=3D ~(1 << (minor & 7)); +} + + static inline void drive_stat_acct(int cmd, unsigned long nr_sectors, short disk_index) { @@ -731,7 +778,6 @@ req->rq_status =3D RQ_INACTIVE; req->next =3D NULL; } - memset(ro_bits,0,sizeof(ro_bits)); memset(max_readahead, 0, sizeof(max_readahead)); memset(max_sectors, 0, sizeof(max_sectors)); #ifdef CONFIG_AMIGA_Z2RAM diff -r -u -P -x CVS -x *,v 2.2.6/fs/super.c current/fs/super.c --- 2.2.6/fs/super.c Tue Apr 20 13:41:57 1999 +++ current/fs/super.c Thu Apr 22 18:02:20 1999 @@ -131,6 +131,7 @@ vfsmnttail->mnt_next =3D lptr; vfsmnttail =3D lptr; } + set_device_busy(sb->s_dev,1); out: return lptr; } @@ -165,6 +166,8 @@ kfree(tofree->mnt_devname); kfree(tofree->mnt_dirname); kfree_s(tofree, sizeof(struct vfsmount)); + + set_device_busy(dev,0); } =20 int register_filesystem(struct file_system_type * fs) @@ -873,6 +876,8 @@ if (dir_d->d_covers !=3D dir_d) goto dput_and_out; =20 + if (is_device_busy(dev)) + goto dput_and_out; /* * Note: If the superblock already exists, * read_super just does a get_super(). diff -r -u -P -x CVS -x *,v 2.2.6/include/linux/fs.h = current/include/linux/fs.h --- 2.2.6/include/linux/fs.h Tue Apr 20 13:41:58 1999 +++ current/include/linux/fs.h Thu Apr 22 18:02:20 1999 @@ -839,6 +839,8 @@ extern struct buffer_head * find_buffer(kdev_t dev, int block, int = size); extern void ll_rw_block(int, int, struct buffer_head * bh[]); extern int is_read_only(kdev_t); +extern int is_device_busy(kdev_t); +extern void set_device_busy(kdev_t dev, int flag); extern void __brelse(struct buffer_head *); extern inline void brelse(struct buffer_head *buf) { diff -r -u -P -x CVS -x *,v 2.2.6/kernel/ksyms.c current/kernel/ksyms.c --- 2.2.6/kernel/ksyms.c Wed Mar 31 00:56:57 1999 +++ current/kernel/ksyms.c Thu Apr 22 18:02:20 1999 @@ -47,7 +47,7 @@ #endif =20 extern char *get_options(char *str, int *ints); -extern void set_device_ro(kdev_t dev,int flag); +extern void set_device_ro(kdev_t dev, int flag); extern struct file_operations * get_blkfops(unsigned int); extern int blkdev_release(struct inode * inode); #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE) @@ -209,6 +209,8 @@ EXPORT_SYMBOL(blk_dev); EXPORT_SYMBOL(is_read_only); EXPORT_SYMBOL(set_device_ro); +EXPORT_SYMBOL(is_device_busy); +EXPORT_SYMBOL(set_device_busy); EXPORT_SYMBOL(bmap); EXPORT_SYMBOL(sync_dev); EXPORT_SYMBOL(get_blkfops); diff -r -u -P -x CVS -x *,v 2.2.6/mm/swapfile.c current/mm/swapfile.c --- 2.2.6/mm/swapfile.c Wed Mar 31 00:56:57 1999 +++ current/mm/swapfile.c Thu Apr 22 18:02:20 1999 @@ -414,6 +414,7 @@ filp.f_op->release(dentry->d_inode,&filp); filp.f_op->release(dentry->d_inode,&filp); } + set_device_busy(p->swap_device,0); } dput(dentry); =20 @@ -531,6 +532,10 @@ =20 if (S_ISBLK(swap_dentry->d_inode->i_mode)) { p->swap_device =3D swap_dentry->d_inode->i_rdev; + if(is_device_busy(p->swap_device)) { + error =3D -EBUSY; + goto bad_swap; + } set_blocksize(p->swap_device, PAGE_SIZE); =09 filp.f_dentry =3D swap_dentry; @@ -686,6 +691,8 @@ swap_info[prev].next =3D p - swap_info; } error =3D 0; + if(p->swap_device !=3D 0) + set_device_busy(p->swap_device,1); goto out; bad_swap: if(filp.f_op && filp.f_op->release)

------=_NextPart_000_001C_01BEAF9F.E8D9EED0--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/