From b54cee93b40ef775f12206d68f04fb8bb5edbfe9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 4 Feb 2002 23:58:33 -0800 Subject: v2.5.0.6 -> v2.5.0.7 - Jens Axboe: more bio fixes/cleanups/breakage ;) - Al Viro: superblock cleanups, boot/root mounting. --- Makefile | 9 +- arch/i386/kernel/pci-pc.c | 24 +- drivers/block/elevator.c | 14 ++ drivers/block/floppy.c | 2 +- drivers/block/ll_rw_blk.c | 26 ++- drivers/char/pc_keyb.c | 2 +- fs/bio.c | 16 +- fs/namespace.c | 142 ++++-------- fs/super.c | 297 +++--------------------- include/linux/bio.h | 12 +- include/linux/blk.h | 3 + include/linux/device.h | 4 - include/linux/fs.h | 2 - include/linux/pci_ids.h | 6 +- init/do_mounts.c | 558 ++++++++++++++++++++++++++++++++++++++++++++++ init/main.c | 267 +--------------------- kernel/device.c | 113 ++-------- mm/highmem.c | 52 +++-- 18 files changed, 758 insertions(+), 791 deletions(-) create mode 100644 init/do_mounts.c diff --git a/Makefile b/Makefile index 098baecc6dde..6f809123df89 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 1 -EXTRAVERSION =-pre6 +EXTRAVERSION =-pre7 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -257,8 +257,8 @@ Version: dummy boot: vmlinux @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C arch/$(ARCH)/boot -vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o linuxsubdirs - $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ +vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o init/do_mounts.o linuxsubdirs + $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \ --start-group \ $(CORE_FILES) \ $(DRIVERS) \ @@ -335,6 +335,9 @@ init/version.o: init/version.c include/linux/compile.h include/config/MARKER init/main.o: init/main.c include/config/MARKER $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -c -o $*.o $< +init/do_mounts.o: init/do_mounts.c include/config/MARKER + $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -c -o $*.o $< + fs lib mm ipc kernel drivers net: dummy $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c index d22a0d0f1b80..bf3fad221750 100644 --- a/arch/i386/kernel/pci-pc.c +++ b/arch/i386/kernel/pci-pc.c @@ -1114,17 +1114,26 @@ static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d) * But it does seem to fix some unspecified problem * with 'movntq' copies on Athlons. * - * VIA 8363 chipset: - * - bit 7 at offset 0x55: Debug (RW) + * VIA 8363,8622,8361 Northbridges: + * - bits 5, 6, 7 at offset 0x55 need to be turned off + * VIA 8367 (KT266x) Northbridges: + * - bits 5, 6, 7 at offset 0x95 need to be turned off */ static void __init pci_fixup_via_athlon_bug(struct pci_dev *d) { u8 v; - pci_read_config_byte(d, 0x55, &v); - if (v & 0x80) { + int where = 0x55; + + if (d->device == PCI_DEVICE_ID_VIA_8367_0) { + where = 0x95; /* the memory write queue timer register is + different for the kt266x's: 0x95 not 0x55 */ + } + + pci_read_config_byte(d, where, &v); + if (v & 0xe0) { printk("Trying to stomp on Athlon bug...\n"); - v &= 0x7f; /* clear bit 55.7 */ - pci_write_config_byte(d, 0x55, v); + v &= 0x1f; /* clear bits 5, 6, 7 */ + pci_write_config_byte(d, where, v); } } @@ -1138,6 +1147,9 @@ struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_athlon_bug }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_athlon_bug }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_athlon_bug }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_athlon_bug }, { 0 } }; diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index a904e7541654..c6a23542eb25 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -60,6 +60,12 @@ inline int bio_rq_in_between(struct bio *bio, struct request *rq, BUG_ON(next_rq->flags & REQ_STARTED); + /* + * not a sector based request + */ + if (!(next_rq->flags & REQ_CMD)) + return 0; + /* * if the device is different (not a normal case) just check if * bio is after rq @@ -95,6 +101,9 @@ inline int bio_rq_in_between(struct bio *bio, struct request *rq, */ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio) { + if (!(rq->flags & REQ_CMD)) + return 0; + /* * different data direction or already started, don't merge */ @@ -133,6 +142,8 @@ int elevator_linus_merge(request_queue_t *q, struct request **req, break; if (__rq->flags & (REQ_BARRIER | REQ_STARTED)) break; + if (!(__rq->flags & REQ_CMD)) + continue; if (!*req && bio_rq_in_between(bio, __rq, &q->queue_head)) *req = __rq; @@ -226,6 +237,9 @@ int elevator_noop_merge(request_queue_t *q, struct request **req, if (__rq->flags & (REQ_BARRIER | REQ_STARTED)) break; + if (!(__rq->flags & REQ_CMD)) + continue; + if (!elv_rq_merge_ok(__rq, bio)) continue; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 837587bc5b64..897f3c886b45 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3914,7 +3914,7 @@ static void __init register_devfs_entries (int drive) {NULL, t360, t1200, t3in+5+8, t3in+5, t3in, t3in}; base_minor = (drive < 4) ? drive : (124 + drive); - if (UDP->cmos <= NUMBER(default_drive_params)) { + if (UDP->cmos < NUMBER(default_drive_params)) { i = 0; do { char name[16]; diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 1242a790b3fa..6b92a30291c6 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -291,13 +291,13 @@ static int ll_10byte_cmd_build(request_queue_t *q, struct request *rq) if (!(rq->flags & REQ_CMD)) return 0; + memset(rq->cmd, 0, sizeof(rq->cmd)); + if (rq_data_dir(rq) == READ) rq->cmd[0] = READ_10; else rq->cmd[0] = WRITE_10; - rq->cmd[1] = 0; - /* * fill in lba */ @@ -305,7 +305,6 @@ static int ll_10byte_cmd_build(request_queue_t *q, struct request *rq) rq->cmd[3] = (block >> 16) & 0xff; rq->cmd[4] = (block >> 8) & 0xff; rq->cmd[5] = block & 0xff; - rq->cmd[6] = 0; /* * and transfer length @@ -347,7 +346,7 @@ int blk_rq_map_sg(request_queue_t *q, struct request *rq, struct scatterlist *sg unsigned long long lastend; struct bio_vec *bvec; struct bio *bio; - int nsegs, i, cluster, j; + int nsegs, i, cluster; nsegs = 0; bio = rq->bio; @@ -357,9 +356,7 @@ int blk_rq_map_sg(request_queue_t *q, struct request *rq, struct scatterlist *sg /* * for each bio in rq */ - j = 0; rq_for_each_bio(bio, rq) { - j++; /* * for each segment in bio */ @@ -386,7 +383,6 @@ int blk_rq_map_sg(request_queue_t *q, struct request *rq, struct scatterlist *sg new_segment: if (nsegs > q->max_segments) { printk("map: %d >= %d\n", nsegs, q->max_segments); - printk("map %d, %d, bio_sectors %d, vcnt %d\n", i, j, bio_sectors(bio), bio->bi_vcnt); BUG(); } @@ -411,7 +407,7 @@ new_segment: static inline int ll_new_segment(request_queue_t *q, struct request *req, struct bio *bio) { - if (req->nr_segments + bio->bi_vcnt < q->max_segments) { + if (req->nr_segments + bio->bi_vcnt <= q->max_segments) { req->nr_segments += bio->bi_vcnt; return 1; } @@ -480,9 +476,17 @@ void blk_plug_device(request_queue_t *q) */ static inline void __generic_unplug_device(request_queue_t *q) { - if (test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) - if (!elv_queue_empty(q)) - q->request_fn(q); + /* + * not plugged + */ + if (!test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) + return; + + /* + * was plugged, fire request_fn if queue has stuff to do + */ + if (!elv_queue_empty(q)) + q->request_fn(q); } /** diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c index 657e4488b189..2fc5e15be60b 100644 --- a/drivers/char/pc_keyb.c +++ b/drivers/char/pc_keyb.c @@ -1090,6 +1090,7 @@ static int open_aux(struct inode * inode, struct file * file) spin_unlock_irqrestore(&aux_count_lock, flags); return -EBUSY; } + spin_unlock_irqrestore(&aux_count_lock, flags); kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the auxiliary port on controller. */ @@ -1099,7 +1100,6 @@ static int open_aux(struct inode * inode, struct file * file) mdelay(2); /* Ensure we follow the kbc access delay rules.. */ send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */ - spin_unlock_irqrestore(&aux_count_lock, flags); return 0; } diff --git a/fs/bio.c b/fs/bio.c index 090800657099..76539b360ad7 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -377,7 +377,7 @@ struct bio *bio_copy(struct bio *bio, int gfp_mask, int copy) /* * iterate iovec list and alloc pages + copy data */ - bio_for_each_segment(bv, bio, i) { + __bio_for_each_segment(bv, bio, i, 0) { struct bio_vec *bbv = &b->bi_io_vec[i]; char *vfrom, *vto; @@ -392,8 +392,7 @@ struct bio *bio_copy(struct bio *bio, int gfp_mask, int copy) vfrom = kmap(bv->bv_page); vto = kmap(bbv->bv_page); } else { - __save_flags(flags); - __cli(); + local_irq_save(flags); vfrom = kmap_atomic(bv->bv_page, KM_BIO_IRQ); vto = kmap_atomic(bbv->bv_page, KM_BIO_IRQ); } @@ -405,7 +404,7 @@ struct bio *bio_copy(struct bio *bio, int gfp_mask, int copy) } else { kunmap_atomic(vto, KM_BIO_IRQ); kunmap_atomic(vfrom, KM_BIO_IRQ); - __restore_flags(flags); + local_irq_restore(flags); } fill_in: @@ -424,10 +423,8 @@ fill_in: return b; oom: - while (i >= 0) { + while (--i >= 0) __free_page(b->bi_io_vec[i].bv_page); - i--; - } bio_pool_put(b); return NULL; @@ -613,6 +610,11 @@ out: if (err) kio->errno = err; + /* + * final atomic_dec of io_count to match our initial setting of 1. + * I/O may or may not have completed at this point, final completion + * handler is only run on last decrement. + */ end_kio_request(kio, !err); } diff --git a/fs/namespace.c b/fs/namespace.c index 327e314a2575..d790be367296 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -15,12 +15,10 @@ #include #include #include -#include +#include #include -#include - struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data); int do_remount_sb(struct super_block *sb, int flags, void * data); void kill_super(struct super_block *sb); @@ -31,9 +29,7 @@ static kmem_cache_t *mnt_cache; static LIST_HEAD(vfsmntlist); static DECLARE_MUTEX(mount_sem); - -/* Will be static */ -struct vfsmount *root_vfsmnt; +static struct vfsmount *root_vfsmnt; static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { @@ -462,8 +458,7 @@ Enomem: return NULL; } -/* Will become static */ -int graft_tree(struct vfsmount *mnt, struct nameidata *nd) +static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) { int err; if (mnt->mnt_sb->s_flags & MS_NOUSER) @@ -928,6 +923,44 @@ out3: * In 2.5 we'll use ramfs or tmpfs, but for now it's all we need - just * something to go with root vfsmount. */ +static struct inode_operations rootfs_dir_inode_operations; +static struct file_operations rootfs_dir_operations; +static int rootfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + struct inode * inode = new_inode(dir->i_sb); + int error = -ENOSPC; + if (inode) { + inode->i_mode = S_IFDIR|mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_op = &rootfs_dir_inode_operations; + inode->i_fop = &rootfs_dir_operations; + d_instantiate(dentry, inode); + dget(dentry); + error = 0; + } + return error; +} +static int rootfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) +{ + struct inode * inode = new_inode(dir->i_sb); + int error = -ENOSPC; + if (inode) { + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + init_special_inode(inode, mode, dev); + d_instantiate(dentry, inode); + dget(dentry); + error = 0; + } + return error; +} +static int rootfs_unlink(struct inode * dir, struct dentry *dentry) +{ + dentry->d_inode->i_nlink--; + dput(dentry); + return 0; +} static struct dentry *rootfs_lookup(struct inode *dir, struct dentry *dentry) { d_add(dentry, NULL); @@ -939,6 +972,9 @@ static struct file_operations rootfs_dir_operations = { }; static struct inode_operations rootfs_dir_inode_operations = { lookup: rootfs_lookup, + mkdir: rootfs_mkdir, + mknod: rootfs_mknod, + unlink: rootfs_unlink, }; static struct super_block *rootfs_read_super(struct super_block * sb, void * data, int silent) { @@ -1030,93 +1066,3 @@ void __init mnt_init(unsigned long mempages) } while (i); init_mount_tree(); } - -#ifdef CONFIG_BLK_DEV_INITRD - -int __init change_root(kdev_t new_root_dev,const char *put_old) -{ - struct vfsmount *old_rootmnt; - struct nameidata devfs_nd, nd; - struct nameidata parent_nd; - char *new_devname = kmalloc(strlen("/dev/root.old")+1, GFP_KERNEL); - int error = 0; - - if (new_devname) - strcpy(new_devname, "/dev/root.old"); - - read_lock(¤t->fs->lock); - old_rootmnt = mntget(current->fs->rootmnt); - read_unlock(¤t->fs->lock); - /* First unmount devfs if mounted */ - if (path_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd)) - error = path_walk("/dev", &devfs_nd); - if (!error) { - if (devfs_nd.mnt->mnt_sb->s_magic == DEVFS_SUPER_MAGIC && - devfs_nd.dentry == devfs_nd.mnt->mnt_root) { - do_umount(devfs_nd.mnt, 0); - } - path_release(&devfs_nd); - } - set_fs_pwd(current->fs, root_vfsmnt, root_vfsmnt->mnt_root); - set_fs_root(current->fs, root_vfsmnt, root_vfsmnt->mnt_root); - spin_lock(&dcache_lock); - detach_mnt(old_rootmnt, &parent_nd); - spin_unlock(&dcache_lock); - ROOT_DEV = new_root_dev; - mount_root(); -#if 1 - shrink_dcache(); - printk("change_root: old root has d_count=%d\n", - atomic_read(&old_rootmnt->mnt_root->d_count)); -#endif - mount_devfs_fs (); - /* - * Get the new mount directory - */ - error = 0; - if (path_init(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd)) - error = path_walk(put_old, &nd); - if (error) { - int blivet; - struct block_device *ramdisk = old_rootmnt->mnt_sb->s_bdev; - - atomic_inc(&ramdisk->bd_count); - blivet = blkdev_get(ramdisk, FMODE_READ, 0, BDEV_FS); - printk(KERN_NOTICE "Trying to unmount old root ... "); - if (!blivet) { - spin_lock(&dcache_lock); - list_del_init(&old_rootmnt->mnt_list); - spin_unlock(&dcache_lock); - mntput(old_rootmnt); - mntput(old_rootmnt); - blivet = ioctl_by_bdev(ramdisk, BLKFLSBUF, 0); - path_release(&parent_nd); - blkdev_put(ramdisk, BDEV_FS); - } - if (blivet) { - printk(KERN_ERR "error %d\n", blivet); - } else { - printk("okay\n"); - error = 0; - } - kfree(new_devname); - return error; - } - - spin_lock(&dcache_lock); - attach_mnt(old_rootmnt, &nd); - if (new_devname) { - if (old_rootmnt->mnt_devname) - kfree(old_rootmnt->mnt_devname); - old_rootmnt->mnt_devname = new_devname; - } - spin_unlock(&dcache_lock); - - /* put the old stuff */ - path_release(&parent_nd); - mntput(old_rootmnt); - path_release(&nd); - return 0; -} - -#endif diff --git a/fs/super.c b/fs/super.c index 6e486444c643..368a1087e4eb 100644 --- a/fs/super.c +++ b/fs/super.c @@ -21,36 +21,21 @@ */ #include -#include #include #include #include #include -#include -#include #include -#include #include #include -#include -#include -#include - #include #define __NO_VERSION__ #include -extern void wait_for_keypress(void); - -extern int root_mountflags; - int do_remount_sb(struct super_block *sb, int flags, void * data); -/* this is initialized in init/main.c */ -kdev_t ROOT_DEV; - LIST_HEAD(super_blocks); spinlock_t sb_lock = SPIN_LOCK_UNLOCKED; @@ -429,10 +414,6 @@ struct vfsmount *alloc_vfsmnt(void); void free_vfsmnt(struct vfsmount *mnt); void set_devname(struct vfsmount *mnt, const char *name); -/* Will go away */ -extern struct vfsmount *root_vfsmnt; -extern int graft_tree(struct vfsmount *mnt, struct nameidata *nd); - static inline struct super_block * find_super(kdev_t dev) { struct list_head *p; @@ -549,37 +530,6 @@ out: return err; } -static struct super_block * read_super(kdev_t dev, struct block_device *bdev, - struct file_system_type *type, int flags, - void *data) -{ - struct super_block * s; - s = alloc_super(); - if (!s) - goto out; - s->s_dev = dev; - s->s_bdev = bdev; - s->s_flags = flags; - spin_lock(&sb_lock); - insert_super(s, type); - lock_super(s); - if (!type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) - goto out_fail; - s->s_flags |= MS_ACTIVE; - unlock_super(s); - /* tell bdcache that we are going to keep this one */ - if (bdev) - atomic_inc(&bdev->bd_count); -out: - return s; - -out_fail: - unlock_super(s); - deactivate_super(s); - remove_super(s); - return NULL; -} - /* * Unnamed block devices are dummy devices used by virtual * filesystems which don't use real block-devices. -- jrs @@ -708,17 +658,30 @@ out: static struct super_block *get_sb_nodev(struct file_system_type *fs_type, int flags, void * data) { - kdev_t dev; - int error = -EMFILE; - dev = get_unnamed_dev(); - if (dev) { - struct super_block * sb; - error = -EINVAL; - sb = read_super(dev, NULL, fs_type, flags, data); - if (sb) - return sb; + struct super_block *s = alloc_super(); + + if (!s) + return ERR_PTR(-ENOMEM); + s->s_dev = get_unnamed_dev(); + if (!s->s_dev) { + destroy_super(s); + return ERR_PTR(-EMFILE); } - return ERR_PTR(error); + s->s_flags = flags; + spin_lock(&sb_lock); + insert_super(s, fs_type); + lock_super(s); + if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) + goto out_fail; + s->s_flags |= MS_ACTIVE; + unlock_super(s); + return s; + +out_fail: + unlock_super(s); + deactivate_super(s); + remove_super(s); + return ERR_PTR(-EINVAL); } static struct super_block *get_sb_single(struct file_system_type *fs_type, @@ -743,13 +706,12 @@ retry: do_remount_sb(old, flags, data); return old; } else { - kdev_t dev = get_unnamed_dev(); - if (!dev) { + s->s_dev = get_unnamed_dev(); + if (!s->s_dev) { spin_unlock(&sb_lock); destroy_super(s); return ERR_PTR(-EMFILE); } - s->s_dev = dev; s->s_flags = flags; insert_super(s, fs_type); lock_super(s); @@ -899,212 +861,3 @@ struct vfsmount *kern_mount(struct file_system_type *type) { return do_kern_mount((char *)type->name, 0, (char *)type->name, NULL); } - -static char * __initdata root_mount_data; -static int __init root_data_setup(char *str) -{ - root_mount_data = str; - return 1; -} - -static char * __initdata root_fs_names; -static int __init fs_names_setup(char *str) -{ - root_fs_names = str; - return 1; -} - -__setup("rootflags=", root_data_setup); -__setup("rootfstype=", fs_names_setup); - -static void __init get_fs_names(char *page) -{ - char *s = page; - - if (root_fs_names) { - strcpy(page, root_fs_names); - while (*s++) { - if (s[-1] == ',') - s[-1] = '\0'; - } - } else { - int len = get_filesystem_list(page); - char *p, *next; - - page[len] = '\0'; - for (p = page-1; p; p = next) { - next = strchr(++p, '\n'); - if (*p++ != '\t') - continue; - while ((*s++ = *p++) != '\n') - ; - s[-1] = '\0'; - } - } - *s = '\0'; -} - -void __init mount_root(void) -{ - struct nameidata root_nd; - struct super_block * sb; - struct vfsmount *vfsmnt; - struct block_device *bdev = NULL; - mode_t mode; - int retval; - void *handle; - char path[64]; - char *name = "/dev/root"; - char *fs_names, *p; -#ifdef CONFIG_ROOT_NFS - void *data; -#endif - root_mountflags |= MS_VERBOSE; - -#ifdef CONFIG_ROOT_NFS - if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR) - goto skip_nfs; - data = nfs_root_data(); - if (!data) - goto no_nfs; - vfsmnt = do_kern_mount("nfs", root_mountflags, "/dev/root", data); - if (!IS_ERR(vfsmnt)) { - printk ("VFS: Mounted root (%s filesystem).\n", "nfs"); - ROOT_DEV = vfsmnt->mnt_sb->s_dev; - goto attach_it; - } -no_nfs: - printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); - ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0); -skip_nfs: -#endif - -#ifdef CONFIG_BLK_DEV_FD - if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { -#ifdef CONFIG_BLK_DEV_RAM - extern int rd_doload; - extern void rd_load_secondary(void); -#endif - floppy_eject(); -#ifndef CONFIG_BLK_DEV_RAM - printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n"); -#else - /* rd_doload is 2 for a dual initrd/ramload setup */ - if(rd_doload==2) - rd_load_secondary(); - else -#endif - { - printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n"); - wait_for_keypress(); - } - } -#endif - - fs_names = __getname(); - get_fs_names(fs_names); - - devfs_make_root (root_device_name); - handle = devfs_find_handle (NULL, ROOT_DEVICE_NAME, - MAJOR (ROOT_DEV), MINOR (ROOT_DEV), - DEVFS_SPECIAL_BLK, 1); - if (handle) { - int n; - unsigned major, minor; - - devfs_get_maj_min (handle, &major, &minor); - ROOT_DEV = MKDEV (major, minor); - if (!ROOT_DEV) - panic("I have no root and I want to scream"); - n = devfs_generate_path (handle, path + 5, sizeof (path) - 5); - if (n >= 0) { - name = path + n; - devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT, - name + 5, NULL, NULL); - memcpy (name, "/dev/", 5); - } - } - -retry: - bdev = bdget(kdev_t_to_nr(ROOT_DEV)); - if (!bdev) - panic(__FUNCTION__ ": unable to allocate root device"); - bdev->bd_op = devfs_get_ops (handle); - mode = FMODE_READ; - if (!(root_mountflags & MS_RDONLY)) - mode |= FMODE_WRITE; - retval = blkdev_get(bdev, mode, 0, BDEV_FS); - if (retval == -EROFS) { - root_mountflags |= MS_RDONLY; - goto retry; - } - if (retval) { - /* - * Allow the user to distinguish between failed open - * and bad superblock on root device. - */ -Eio: - printk ("VFS: Cannot open root device \"%s\" or %s\n", - root_device_name, kdevname (ROOT_DEV)); - printk ("Please append a correct \"root=\" boot option\n"); - panic("VFS: Unable to mount root fs on %s", - kdevname(ROOT_DEV)); - } - - check_disk_change(ROOT_DEV); - sb = get_super(ROOT_DEV); - if (sb) { - /* FIXME */ - p = (char *)sb->s_type->name; - atomic_inc(&sb->s_active); - up_read(&sb->s_umount); - down_write(&sb->s_umount); - goto mount_it; - } - - for (p = fs_names; *p; p += strlen(p)+1) { - struct file_system_type * fs_type = get_fs_type(p); - if (!fs_type) - continue; - atomic_inc(&bdev->bd_count); - retval = blkdev_get(bdev, mode, 0, BDEV_FS); - if (retval) - goto Eio; - sb = read_super(ROOT_DEV, bdev, fs_type, - root_mountflags, root_mount_data); - put_filesystem(fs_type); - if (sb) { - blkdev_put(bdev, BDEV_FS); - goto mount_it; - } - } - panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV)); - -mount_it: - /* FIXME */ - up_write(&sb->s_umount); - printk ("VFS: Mounted root (%s filesystem)%s.\n", p, - (sb->s_flags & MS_RDONLY) ? " readonly" : ""); - putname(fs_names); - vfsmnt = alloc_vfsmnt(); - if (!vfsmnt) - panic("VFS: alloc_vfsmnt failed for root fs"); - - set_devname(vfsmnt, name); - vfsmnt->mnt_sb = sb; - vfsmnt->mnt_root = dget(sb->s_root); - bdput(bdev); /* sb holds a reference */ - - -#ifdef CONFIG_ROOT_NFS -attach_it: -#endif - root_nd.mnt = root_vfsmnt; - root_nd.dentry = root_vfsmnt->mnt_sb->s_root; - graft_tree(vfsmnt, &root_nd); - - set_fs_root(current->fs, vfsmnt, vfsmnt->mnt_root); - set_fs_pwd(current->fs, vfsmnt, vfsmnt->mnt_root); - - mntput(vfsmnt); -} diff --git a/include/linux/bio.h b/include/linux/bio.h index 550679134fd8..85e518c1c1e6 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -100,7 +100,6 @@ struct bio { #define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) #define bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_idx) #define bio_page(bio) bio_iovec((bio))->bv_page -#define __bio_offset(bio, idx) bio_iovec_idx((bio), (idx))->bv_offset #define bio_offset(bio) bio_iovec((bio))->bv_offset #define bio_sectors(bio) ((bio)->bi_size >> 9) #define bio_data(bio) (page_address(bio_page((bio))) + bio_offset((bio))) @@ -136,11 +135,18 @@ struct bio { #define bio_io_error(bio) bio_endio((bio), 0, bio_sectors((bio))) -#define bio_for_each_segment(bvl, bio, i) \ - for (bvl = bio_iovec((bio)), i = (bio)->bi_idx; \ +/* + * drivers should not use the __ version unless they _really_ want to + * run through the entire bio and not just pending pieces + */ +#define __bio_for_each_segment(bvl, bio, i, start_idx) \ + for (bvl = bio_iovec_idx((bio), (start_idx)), i = (start_idx); \ i < (bio)->bi_vcnt; \ bvl++, i++) +#define bio_for_each_segment(bvl, bio, i) \ + __bio_for_each_segment(bvl, bio, i, (bio)->bi_idx) + /* * get a reference to a bio, so it won't disappear. the intended use is * something like: diff --git a/include/linux/blk.h b/include/linux/blk.h index 29db6a337ef5..e54f03ebbf02 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -22,6 +22,9 @@ extern void add_blkdev_randomness(int major); extern unsigned long initrd_start,initrd_end; extern int mount_initrd; /* zero if initrd should not be mounted */ extern int initrd_below_start_ok; /* 1 if it is not an error if initrd_start < memory_start */ +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ void initrd_init(void); #endif diff --git a/include/linux/device.h b/include/linux/device.h index df9e1724d3e7..32a2fed4dddd 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -113,10 +113,6 @@ struct iobus_driver { int (*add_device) (struct iobus*, char*); }; -extern int iobus_register_driver(struct iobus_driver * driver); -extern void iobus_unregister_driver(struct iobus_driver * driver); -extern struct iobus_driver * iobus_find_driver(char *name); - struct iobus { spinlock_t lock; /* lock for bus */ atomic_t refcount; diff --git a/include/linux/fs.h b/include/linux/fs.h index 2bc05a6b28b5..7f52b46d619f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1447,11 +1447,9 @@ extern char root_device_name[]; extern void show_buffers(void); -extern void mount_root(void); #ifdef CONFIG_BLK_DEV_INITRD extern unsigned int real_root_dev; -extern int change_root(kdev_t, const char *); #endif extern ssize_t char_read(struct file *, char *, size_t, loff_t *); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index a8753bec73cb..d73d486aba93 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -912,7 +912,7 @@ #define PCI_DEVICE_ID_TTI_HPT366 0x0004 #define PCI_VENDOR_ID_VIA 0x1106 -#define PCI_DEVICE_ID_VIA_8363_0 0x0305 +#define PCI_DEVICE_ID_VIA_8363_0 0x0305 #define PCI_DEVICE_ID_VIA_8371_0 0x0391 #define PCI_DEVICE_ID_VIA_8501_0 0x0501 #define PCI_DEVICE_ID_VIA_82C505 0x0505 @@ -946,9 +946,11 @@ #define PCI_DEVICE_ID_VIA_8233_7 0x3065 #define PCI_DEVICE_ID_VIA_82C686_6 0x3068 #define PCI_DEVICE_ID_VIA_8233_0 0x3074 +#define PCI_DEVICE_ID_VIA_8622 0x3102 #define PCI_DEVICE_ID_VIA_8233C_0 0x3109 +#define PCI_DEVICE_ID_VIA_8361 0x3112 #define PCI_DEVICE_ID_VIA_8633_0 0x3091 -#define PCI_DEVICE_ID_VIA_8367_0 0x3099 +#define PCI_DEVICE_ID_VIA_8367_0 0x3099 #define PCI_DEVICE_ID_VIA_86C100A 0x6100 #define PCI_DEVICE_ID_VIA_8231 0x8231 #define PCI_DEVICE_ID_VIA_8231_4 0x8235 diff --git a/init/do_mounts.c b/init/do_mounts.c new file mode 100644 index 000000000000..8d16e3face51 --- /dev/null +++ b/init/do_mounts.c @@ -0,0 +1,558 @@ +#define __KERNEL_SYSCALLS__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* syscalls missing from unistd.h */ + +static inline _syscall2(int,mkdir,char *,name,int,mode); +static inline _syscall1(int,chdir,char *,name); +static inline _syscall1(int,chroot,char *,name); +static inline _syscall1(int,unlink,char *,name); +static inline _syscall3(int,mknod,char *,name,int,mode,dev_t,dev); +static inline _syscall5(int,mount,char *,dev,char *,dir,char *,type, + unsigned long,flags,void *,data); +static inline _syscall2(int,umount,char *,name,int,flags); + +extern void rd_load(void); +extern void initrd_load(void); + +#ifdef CONFIG_BLK_DEV_INITRD +unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ +#endif +int root_mountflags = MS_RDONLY; +char root_device_name[64]; + +/* this is initialized in init/main.c */ +kdev_t ROOT_DEV; + +static int __init readonly(char *str) +{ + if (*str) + return 0; + root_mountflags |= MS_RDONLY; + return 1; +} + +static int __init readwrite(char *str) +{ + if (*str) + return 0; + root_mountflags &= ~MS_RDONLY; + return 1; +} + +__setup("ro", readonly); +__setup("rw", readwrite); + +static struct dev_name_struct { + const char *name; + const int num; +} root_dev_names[] __initdata = { + { "nfs", 0x00ff }, + { "hda", 0x0300 }, + { "hdb", 0x0340 }, + { "loop", 0x0700 }, + { "hdc", 0x1600 }, + { "hdd", 0x1640 }, + { "hde", 0x2100 }, + { "hdf", 0x2140 }, + { "hdg", 0x2200 }, + { "hdh", 0x2240 }, + { "hdi", 0x3800 }, + { "hdj", 0x3840 }, + { "hdk", 0x3900 }, + { "hdl", 0x3940 }, + { "hdm", 0x5800 }, + { "hdn", 0x5840 }, + { "hdo", 0x5900 }, + { "hdp", 0x5940 }, + { "hdq", 0x5A00 }, + { "hdr", 0x5A40 }, + { "hds", 0x5B00 }, + { "hdt", 0x5B40 }, + { "sda", 0x0800 }, + { "sdb", 0x0810 }, + { "sdc", 0x0820 }, + { "sdd", 0x0830 }, + { "sde", 0x0840 }, + { "sdf", 0x0850 }, + { "sdg", 0x0860 }, + { "sdh", 0x0870 }, + { "sdi", 0x0880 }, + { "sdj", 0x0890 }, + { "sdk", 0x08a0 }, + { "sdl", 0x08b0 }, + { "sdm", 0x08c0 }, + { "sdn", 0x08d0 }, + { "sdo", 0x08e0 }, + { "sdp", 0x08f0 }, + { "ada", 0x1c00 }, + { "adb", 0x1c10 }, + { "adc", 0x1c20 }, + { "add", 0x1c30 }, + { "ade", 0x1c40 }, + { "fd", 0x0200 }, + { "md", 0x0900 }, + { "xda", 0x0d00 }, + { "xdb", 0x0d40 }, + { "ram", 0x0100 }, + { "scd", 0x0b00 }, + { "mcd", 0x1700 }, + { "cdu535", 0x1800 }, + { "sonycd", 0x1800 }, + { "aztcd", 0x1d00 }, + { "cm206cd", 0x2000 }, + { "gscd", 0x1000 }, + { "sbpcd", 0x1900 }, + { "eda", 0x2400 }, + { "edb", 0x2440 }, + { "pda", 0x2d00 }, + { "pdb", 0x2d10 }, + { "pdc", 0x2d20 }, + { "pdd", 0x2d30 }, + { "pcd", 0x2e00 }, + { "pf", 0x2f00 }, + { "apblock", APBLOCK_MAJOR << 8}, + { "ddv", DDV_MAJOR << 8}, + { "jsfd", JSFD_MAJOR << 8}, +#if defined(CONFIG_ARCH_S390) + { "dasda", (DASD_MAJOR << MINORBITS) }, + { "dasdb", (DASD_MAJOR << MINORBITS) + (1 << 2) }, + { "dasdc", (DASD_MAJOR << MINORBITS) + (2 << 2) }, + { "dasdd", (DASD_MAJOR << MINORBITS) + (3 << 2) }, + { "dasde", (DASD_MAJOR << MINORBITS) + (4 << 2) }, + { "dasdf", (DASD_MAJOR << MINORBITS) + (5 << 2) }, + { "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) }, + { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) }, +#endif +#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE) + { "ida/c0d0p",0x4800 }, + { "ida/c0d1p",0x4810 }, + { "ida/c0d2p",0x4820 }, + { "ida/c0d3p",0x4830 }, + { "ida/c0d4p",0x4840 }, + { "ida/c0d5p",0x4850 }, + { "ida/c0d6p",0x4860 }, + { "ida/c0d7p",0x4870 }, + { "ida/c0d8p",0x4880 }, + { "ida/c0d9p",0x4890 }, + { "ida/c0d10p",0x48A0 }, + { "ida/c0d11p",0x48B0 }, + { "ida/c0d12p",0x48C0 }, + { "ida/c0d13p",0x48D0 }, + { "ida/c0d14p",0x48E0 }, + { "ida/c0d15p",0x48F0 }, +#endif +#if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE) + { "cciss/c0d0p",0x6800 }, + { "cciss/c0d1p",0x6810 }, + { "cciss/c0d2p",0x6820 }, + { "cciss/c0d3p",0x6830 }, + { "cciss/c0d4p",0x6840 }, + { "cciss/c0d5p",0x6850 }, + { "cciss/c0d6p",0x6860 }, + { "cciss/c0d7p",0x6870 }, + { "cciss/c0d8p",0x6880 }, + { "cciss/c0d9p",0x6890 }, + { "cciss/c0d10p",0x68A0 }, + { "cciss/c0d11p",0x68B0 }, + { "cciss/c0d12p",0x68C0 }, + { "cciss/c0d13p",0x68D0 }, + { "cciss/c0d14p",0x68E0 }, + { "cciss/c0d15p",0x68F0 }, +#endif + { "nftla", 0x5d00 }, + { "nftlb", 0x5d10 }, + { "nftlc", 0x5d20 }, + { "nftld", 0x5d30 }, + { "ftla", 0x2c00 }, + { "ftlb", 0x2c08 }, + { "ftlc", 0x2c10 }, + { "ftld", 0x2c18 }, + { "mtdblock", 0x1f00 }, + { NULL, 0 } +}; + +kdev_t __init name_to_kdev_t(char *line) +{ + int base = 0; + + if (strncmp(line,"/dev/",5) == 0) { + struct dev_name_struct *dev = root_dev_names; + line += 5; + do { + int len = strlen(dev->name); + if (strncmp(line,dev->name,len) == 0) { + line += len; + base = dev->num; + break; + } + dev++; + } while (dev->name); + } + return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16)); +} + +static int __init root_dev_setup(char *line) +{ + int i; + char ch; + + ROOT_DEV = name_to_kdev_t(line); + memset (root_device_name, 0, sizeof root_device_name); + if (strncmp (line, "/dev/", 5) == 0) line += 5; + for (i = 0; i < sizeof root_device_name - 1; ++i) + { + ch = line[i]; + if ( isspace (ch) || (ch == ',') || (ch == '\0') ) break; + root_device_name[i] = ch; + } + return 1; +} + +__setup("root=", root_dev_setup); + +static char * __initdata root_mount_data; +static int __init root_data_setup(char *str) +{ + root_mount_data = str; + return 1; +} + +static char * __initdata root_fs_names; +static int __init fs_names_setup(char *str) +{ + root_fs_names = str; + return 1; +} + +__setup("rootflags=", root_data_setup); +__setup("rootfstype=", fs_names_setup); + +static void __init get_fs_names(char *page) +{ + char *s = page; + + if (root_fs_names) { + strcpy(page, root_fs_names); + while (*s++) { + if (s[-1] == ',') + s[-1] = '\0'; + } + } else { + int len = get_filesystem_list(page); + char *p, *next; + + page[len] = '\0'; + for (p = page-1; p; p = next) { + next = strchr(++p, '\n'); + if (*p++ != '\t') + continue; + while ((*s++ = *p++) != '\n') + ; + s[-1] = '\0'; + } + } + *s = '\0'; +} + +static void __init mount_root(void) +{ + void *handle; + char path[64]; + char *name = "/dev/root"; + char *fs_names, *p; + int err; + int do_devfs = 0; +#ifdef CONFIG_ROOT_NFS + void *data; +#endif + root_mountflags |= MS_VERBOSE; + + fs_names = __getname(); + get_fs_names(fs_names); + +#ifdef CONFIG_ROOT_NFS + if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR) + goto skip_nfs; + data = nfs_root_data(); + if (!data) + goto no_nfs; + err = mount("/dev/root", "/root", "nfs", root_mountflags, data); + if (!err) + goto done; +no_nfs: + printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); + ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0); +skip_nfs: +#endif + +#ifdef CONFIG_BLK_DEV_FD + if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { +#ifdef CONFIG_BLK_DEV_RAM + extern int rd_doload; + extern void rd_load_secondary(void); +#endif + floppy_eject(); +#ifndef CONFIG_BLK_DEV_RAM + printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n"); +#else + /* rd_doload is 2 for a dual initrd/ramload setup */ + if(rd_doload==2) + rd_load_secondary(); + else +#endif + { + printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n"); + wait_for_keypress(); + } + } +#endif + + devfs_make_root (root_device_name); + handle = devfs_find_handle (NULL, ROOT_DEVICE_NAME, + MAJOR (ROOT_DEV), MINOR (ROOT_DEV), + DEVFS_SPECIAL_BLK, 1); + if (handle) { + int n; + unsigned major, minor; + + devfs_get_maj_min (handle, &major, &minor); + ROOT_DEV = MKDEV (major, minor); + if (!ROOT_DEV) + panic("I have no root and I want to scream"); + n = devfs_generate_path (handle, path + 5, sizeof (path) - 5); + if (n >= 0) { + name = path + n; + devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT, + name + 5, NULL, NULL); + memcpy (name, "/dev/", 5); + do_devfs = 1; + } + } + chdir("/dev"); + unlink("root"); + mknod("root", S_IFBLK|0600, kdev_t_to_nr(ROOT_DEV)); + if (do_devfs) + mount("devfs", ".", "devfs", 0, NULL); +retry: + for (p = fs_names; *p; p += strlen(p)+1) { + err = mount(name,"/root",p,root_mountflags,root_mount_data); + switch (err) { + case 0: + goto done; + case -EACCES: + root_mountflags |= MS_RDONLY; + goto retry; + case -EINVAL: + continue; + } + /* + * Allow the user to distinguish between failed open + * and bad superblock on root device. + */ + printk ("VFS: Cannot open root device \"%s\" or %s\n", + root_device_name, kdevname (ROOT_DEV)); + printk ("Please append a correct \"root=\" boot option\n"); + panic("VFS: Unable to mount root fs on %s", + kdevname(ROOT_DEV)); + } + panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV)); + +done: + putname(fs_names); + if (do_devfs) + umount(".", 0); +} + +#ifdef CONFIG_BLK_DEV_INITRD + +static int __init change_root(kdev_t new_root_dev,const char *put_old) +{ + struct vfsmount *old_rootmnt; + struct nameidata devfs_nd; + char *new_devname = kmalloc(strlen("/dev/root.old")+1, GFP_KERNEL); + int error = 0; + + if (new_devname) + strcpy(new_devname, "/dev/root.old"); + + /* .. here is directory mounted over root */ + mount("..", ".", NULL, MS_MOVE, NULL); + chdir("/old"); + + read_lock(¤t->fs->lock); + old_rootmnt = mntget(current->fs->pwdmnt); + read_unlock(¤t->fs->lock); + + /* First unmount devfs if mounted */ + if (path_init("/old/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd)) + error = path_walk("/old/dev", &devfs_nd); + if (!error) { + if (devfs_nd.mnt->mnt_sb->s_magic == DEVFS_SUPER_MAGIC && + devfs_nd.dentry == devfs_nd.mnt->mnt_root) + umount("/old/dev", 0); + path_release(&devfs_nd); + } + + ROOT_DEV = new_root_dev; + mount_root(); + + chdir("/root"); + ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; + printk("VFS: Mounted root (%s filesystem)%s.\n", + current->fs->pwdmnt->mnt_sb->s_type->name, + (current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY) ? " readonly" : ""); + +#if 1 + shrink_dcache(); + printk("change_root: old root has d_count=%d\n", + atomic_read(&old_rootmnt->mnt_root->d_count)); +#endif + + error = mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); + if (error) { + int blivet; + struct block_device *ramdisk = old_rootmnt->mnt_sb->s_bdev; + + atomic_inc(&ramdisk->bd_count); + blivet = blkdev_get(ramdisk, FMODE_READ, 0, BDEV_FS); + printk(KERN_NOTICE "Trying to unmount old root ... "); + umount("/old", MNT_DETACH); + if (!blivet) { + blivet = ioctl_by_bdev(ramdisk, BLKFLSBUF, 0); + blkdev_put(ramdisk, BDEV_FS); + } + if (blivet) { + printk(KERN_ERR "error %d\n", blivet); + } else { + printk("okay\n"); + error = 0; + } + } else { + spin_lock(&dcache_lock); + if (new_devname) { + void *p = old_rootmnt->mnt_devname; + old_rootmnt->mnt_devname = new_devname; + new_devname = p; + } + spin_unlock(&dcache_lock); + } + + /* put the old stuff */ + mntput(old_rootmnt); + kfree(new_devname); + return error; +} + +#endif + +#ifdef CONFIG_BLK_DEV_INITRD +static int do_linuxrc(void * shell) +{ + static char *argv[] = { "linuxrc", NULL, }; + extern char * envp_init[]; + + chdir("/root"); + mount(".", "/", NULL, MS_MOVE, NULL); + chroot("."); + + mount_devfs_fs (); + + close(0);close(1);close(2); + setsid(); + (void) open("/dev/console",O_RDWR,0); + (void) dup(0); + (void) dup(0); + return execve(shell, argv, envp_init); +} + +#endif + +/* + * Prepare the namespace - decide what/where to mount, load ramdisks, etc. + */ +void prepare_namespace(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + int real_root_mountflags = root_mountflags; + if (!initrd_start) + mount_initrd = 0; + if (mount_initrd) + root_mountflags &= ~MS_RDONLY; + real_root_dev = ROOT_DEV; +#endif + mkdir("/dev", 0700); + mkdir("/root", 0700); + +#ifdef CONFIG_BLK_DEV_RAM +#ifdef CONFIG_BLK_DEV_INITRD + if (mount_initrd) + initrd_load(); + else +#endif + rd_load(); +#endif + + /* Mount the root filesystem.. */ + mount_root(); + chdir("/root"); + ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; + printk("VFS: Mounted root (%s filesystem)%s.\n", + current->fs->pwdmnt->mnt_sb->s_type->name, + (current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY) ? " readonly" : ""); + +#ifdef CONFIG_BLK_DEV_INITRD + root_mountflags = real_root_mountflags; + if (mount_initrd && ROOT_DEV != real_root_dev + && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { + int error; + int i, pid; + mkdir("/old", 0700); + chdir("/old"); + + pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); + if (pid > 0) { + while (pid != wait(&i)) { + current->policy |= SCHED_YIELD; + schedule(); + } + } + if (MAJOR(real_root_dev) != RAMDISK_MAJOR + || MINOR(real_root_dev) != 0) { + error = change_root(real_root_dev,"/initrd"); + if (error) + printk(KERN_ERR "Change root to /initrd: " + "error %d\n",error); + + chdir("/root"); + mount(".", "/", NULL, MS_MOVE, NULL); + chroot("."); + + mount_devfs_fs (); + return; + } + chroot(".."); + chdir("/"); + return; + } +#endif + mount(".", "/", NULL, MS_MOVE, NULL); + chroot("."); + + mount_devfs_fs (); +} diff --git a/init/main.c b/init/main.c index b0e3304513e8..c7e9d0faa42a 100644 --- a/init/main.c +++ b/init/main.c @@ -120,17 +120,10 @@ extern void softirq_init(void); int rows, cols; -#ifdef CONFIG_BLK_DEV_INITRD -unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ -#endif - -int root_mountflags = MS_RDONLY; char *execute_command; -char root_device_name[64]; - static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; -static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; +char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; static int __init profile_setup(char *str) { @@ -141,175 +134,6 @@ static int __init profile_setup(char *str) __setup("profile=", profile_setup); - -static struct dev_name_struct { - const char *name; - const int num; -} root_dev_names[] __initdata = { - { "nfs", 0x00ff }, - { "hda", 0x0300 }, - { "hdb", 0x0340 }, - { "loop", 0x0700 }, - { "hdc", 0x1600 }, - { "hdd", 0x1640 }, - { "hde", 0x2100 }, - { "hdf", 0x2140 }, - { "hdg", 0x2200 }, - { "hdh", 0x2240 }, - { "hdi", 0x3800 }, - { "hdj", 0x3840 }, - { "hdk", 0x3900 }, - { "hdl", 0x3940 }, - { "hdm", 0x5800 }, - { "hdn", 0x5840 }, - { "hdo", 0x5900 }, - { "hdp", 0x5940 }, - { "hdq", 0x5A00 }, - { "hdr", 0x5A40 }, - { "hds", 0x5B00 }, - { "hdt", 0x5B40 }, - { "sda", 0x0800 }, - { "sdb", 0x0810 }, - { "sdc", 0x0820 }, - { "sdd", 0x0830 }, - { "sde", 0x0840 }, - { "sdf", 0x0850 }, - { "sdg", 0x0860 }, - { "sdh", 0x0870 }, - { "sdi", 0x0880 }, - { "sdj", 0x0890 }, - { "sdk", 0x08a0 }, - { "sdl", 0x08b0 }, - { "sdm", 0x08c0 }, - { "sdn", 0x08d0 }, - { "sdo", 0x08e0 }, - { "sdp", 0x08f0 }, - { "ada", 0x1c00 }, - { "adb", 0x1c10 }, - { "adc", 0x1c20 }, - { "add", 0x1c30 }, - { "ade", 0x1c40 }, - { "fd", 0x0200 }, - { "md", 0x0900 }, - { "xda", 0x0d00 }, - { "xdb", 0x0d40 }, - { "ram", 0x0100 }, - { "scd", 0x0b00 }, - { "mcd", 0x1700 }, - { "cdu535", 0x1800 }, - { "sonycd", 0x1800 }, - { "aztcd", 0x1d00 }, - { "cm206cd", 0x2000 }, - { "gscd", 0x1000 }, - { "sbpcd", 0x1900 }, - { "eda", 0x2400 }, - { "edb", 0x2440 }, - { "pda", 0x2d00 }, - { "pdb", 0x2d10 }, - { "pdc", 0x2d20 }, - { "pdd", 0x2d30 }, - { "pcd", 0x2e00 }, - { "pf", 0x2f00 }, - { "apblock", APBLOCK_MAJOR << 8}, - { "ddv", DDV_MAJOR << 8}, - { "jsfd", JSFD_MAJOR << 8}, -#if defined(CONFIG_ARCH_S390) - { "dasda", (DASD_MAJOR << MINORBITS) }, - { "dasdb", (DASD_MAJOR << MINORBITS) + (1 << 2) }, - { "dasdc", (DASD_MAJOR << MINORBITS) + (2 << 2) }, - { "dasdd", (DASD_MAJOR << MINORBITS) + (3 << 2) }, - { "dasde", (DASD_MAJOR << MINORBITS) + (4 << 2) }, - { "dasdf", (DASD_MAJOR << MINORBITS) + (5 << 2) }, - { "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) }, - { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) }, -#endif -#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE) - { "ida/c0d0p",0x4800 }, - { "ida/c0d1p",0x4810 }, - { "ida/c0d2p",0x4820 }, - { "ida/c0d3p",0x4830 }, - { "ida/c0d4p",0x4840 }, - { "ida/c0d5p",0x4850 }, - { "ida/c0d6p",0x4860 }, - { "ida/c0d7p",0x4870 }, - { "ida/c0d8p",0x4880 }, - { "ida/c0d9p",0x4890 }, - { "ida/c0d10p",0x48A0 }, - { "ida/c0d11p",0x48B0 }, - { "ida/c0d12p",0x48C0 }, - { "ida/c0d13p",0x48D0 }, - { "ida/c0d14p",0x48E0 }, - { "ida/c0d15p",0x48F0 }, -#endif -#if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE) - { "cciss/c0d0p",0x6800 }, - { "cciss/c0d1p",0x6810 }, - { "cciss/c0d2p",0x6820 }, - { "cciss/c0d3p",0x6830 }, - { "cciss/c0d4p",0x6840 }, - { "cciss/c0d5p",0x6850 }, - { "cciss/c0d6p",0x6860 }, - { "cciss/c0d7p",0x6870 }, - { "cciss/c0d8p",0x6880 }, - { "cciss/c0d9p",0x6890 }, - { "cciss/c0d10p",0x68A0 }, - { "cciss/c0d11p",0x68B0 }, - { "cciss/c0d12p",0x68C0 }, - { "cciss/c0d13p",0x68D0 }, - { "cciss/c0d14p",0x68E0 }, - { "cciss/c0d15p",0x68F0 }, -#endif - { "nftla", 0x5d00 }, - { "nftlb", 0x5d10 }, - { "nftlc", 0x5d20 }, - { "nftld", 0x5d30 }, - { "ftla", 0x2c00 }, - { "ftlb", 0x2c08 }, - { "ftlc", 0x2c10 }, - { "ftld", 0x2c18 }, - { "mtdblock", 0x1f00 }, - { NULL, 0 } -}; - -kdev_t __init name_to_kdev_t(char *line) -{ - int base = 0; - - if (strncmp(line,"/dev/",5) == 0) { - struct dev_name_struct *dev = root_dev_names; - line += 5; - do { - int len = strlen(dev->name); - if (strncmp(line,dev->name,len) == 0) { - line += len; - base = dev->num; - break; - } - dev++; - } while (dev->name); - } - return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16)); -} - -static int __init root_dev_setup(char *line) -{ - int i; - char ch; - - ROOT_DEV = name_to_kdev_t(line); - memset (root_device_name, 0, sizeof root_device_name); - if (strncmp (line, "/dev/", 5) == 0) line += 5; - for (i = 0; i < sizeof root_device_name - 1; ++i) - { - ch = line[i]; - if ( isspace (ch) || (ch == ',') || (ch == '\0') ) break; - root_device_name[i] = ch; - } - return 1; -} - -__setup("root=", root_dev_setup); - static int __init checksetup(char *line) { struct kernel_param *p; @@ -376,22 +200,6 @@ void __init calibrate_delay(void) (loops_per_jiffy/(5000/HZ)) % 100); } -static int __init readonly(char *str) -{ - if (*str) - return 0; - root_mountflags |= MS_RDONLY; - return 1; -} - -static int __init readwrite(char *str) -{ - if (*str) - return 0; - root_mountflags &= ~MS_RDONLY; - return 1; -} - static int __init debug_kernel(char *str) { if (*str) @@ -408,8 +216,6 @@ static int __init quiet_kernel(char *str) return 1; } -__setup("ro", readonly); -__setup("rw", readwrite); __setup("debug", debug_kernel); __setup("quiet", quiet_kernel); @@ -624,21 +430,6 @@ asmlinkage void __init start_kernel(void) rest_init(); } -#ifdef CONFIG_BLK_DEV_INITRD -static int do_linuxrc(void * shell) -{ - static char *argv[] = { "linuxrc", NULL, }; - - close(0);close(1);close(2); - setsid(); - (void) open("/dev/console",O_RDWR,0); - (void) dup(0); - (void) dup(0); - return execve(shell, argv, envp_init); -} - -#endif - struct task_struct *child_reaper = &init_task; static void __init do_initcalls(void) @@ -745,61 +536,7 @@ static void __init do_basic_setup(void) #endif } -extern void rd_load(void); -extern void initrd_load(void); - -/* - * Prepare the namespace - decide what/where to mount, load ramdisks, etc. - */ -static void prepare_namespace(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - int real_root_mountflags = root_mountflags; - if (!initrd_start) - mount_initrd = 0; - if (mount_initrd) - root_mountflags &= ~MS_RDONLY; - real_root_dev = ROOT_DEV; -#endif - -#ifdef CONFIG_BLK_DEV_RAM -#ifdef CONFIG_BLK_DEV_INITRD - if (mount_initrd) - initrd_load(); - else -#endif - rd_load(); -#endif - - /* Mount the root filesystem.. */ - mount_root(); - - mount_devfs_fs (); - -#ifdef CONFIG_BLK_DEV_INITRD - root_mountflags = real_root_mountflags; - if (mount_initrd && ROOT_DEV != real_root_dev - && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { - int error; - int i, pid; - - pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); - if (pid > 0) { - while (pid != wait(&i)) { - current->policy |= SCHED_YIELD; - schedule(); - } - } - if (MAJOR(real_root_dev) != RAMDISK_MAJOR - || MINOR(real_root_dev) != 0) { - error = change_root(real_root_dev,"/initrd"); - if (error) - printk(KERN_ERR "Change root to /initrd: " - "error %d\n",error); - } - } -#endif -} +extern void prepare_namespace(void); static int init(void * unused) { diff --git a/kernel/device.c b/kernel/device.c index 353421226835..06798d64990f 100644 --- a/kernel/device.c +++ b/kernel/device.c @@ -50,11 +50,6 @@ int (*platform_notify)(struct device * dev) = NULL; int (*platform_notify_remove)(struct device * dev) = NULL; static spinlock_t device_lock; -static LIST_HEAD(device_gc_list); - -static int kdeviced_pid = 0; -static DECLARE_WAIT_QUEUE_HEAD(kdeviced_wait); -static DECLARE_COMPLETION(kdeviced_exited); static ssize_t device_read_status(char *, size_t, loff_t, void *); static ssize_t device_write_status(const char *, size_t, loff_t, void *); @@ -379,12 +374,24 @@ void put_device(struct device * dev) list_del_init(&dev->node); unlock_iobus(parent); - /* queue the device to be removed by the reaper. */ - spin_lock(&device_lock); - list_add_tail(&dev->node,&device_gc_list); - spin_unlock(&device_lock); + /* remove the driverfs directory */ + device_remove_dir(dev); + + if (dev->subordinate) + iobus_remove_dir(dev->subordinate); - wake_up(&kdeviced_wait); + /* Notify the platform of the removal, in case they + * need to do anything... + */ + if (platform_notify_remove) + platform_notify_remove(dev); + + /* Tell the driver to clean up after itself. + * Note that we likely didn't allocate the device, + * so this is the driver's chance to free that up... + */ + if (dev->driver && dev->driver->remove) + dev->driver->remove(dev,REMOVE_FREE_RESOURCES); put_iobus(parent); } @@ -875,76 +882,6 @@ static ssize_t iobus_write_status(const char *buf, size_t count, loff_t off, voi return error < 0 ? error : count; } -/* Device Garbage Collection - * When a device's reference count reaches 0, it is removed from it's - * parent's list and added to a list of devices waiting to be removed. - * - * We don't directly remove it ourselves, because someone could have an - * open file. - * - * We don't allocate an event for keventd, becuase we may be here from - * an interrupt; and how do those things get freed, anyway? - * - * Instead, when a device's reference count reaches 0, it is removed - * from its parent's list of children and added to the list of devices - * to be reaped. - * - * When we spawn a thread that gets woken up every time a device is added - * to the unused list. - */ -static inline void __reap_device(struct device * dev) -{ - /* FIXME: What do we do for a bridge? */ - - /* remove the driverfs directory */ - device_remove_dir(dev); - - if (dev->subordinate) - iobus_remove_dir(dev->subordinate); - - /* Notify the platform of the removal, in case they - * need to do anything... - */ - if (platform_notify_remove) - platform_notify_remove(dev); - - /* Tell the driver to clean up after itself. - * Note that we likely didn't allocate the device, - * so this is the driver's chance to free that up... - */ - if (dev->driver && dev->driver->remove) - dev->driver->remove(dev,REMOVE_FREE_RESOURCES); -} - -static int device_cleanup_thread(void * data) -{ - daemonize(); - - strcpy(current->comm,"kdeviced"); - - do { - struct list_head * node; - - spin_lock(&device_lock); - node = device_gc_list.next; - while(node != &device_gc_list) { - list_del_init(node); - spin_unlock(&device_lock); - __reap_device(list_to_dev(node)); - - spin_lock(&device_lock); - node = device_gc_list.next; - } - spin_unlock(&device_lock); - - interruptible_sleep_on(&kdeviced_wait); - } while(!signal_pending(current)); - - DBG("kdeviced exiting\n"); - complete_and_exit(&kdeviced_exited,0); - return 0; -} - static int __init device_init_root(void) { /* initialize parent bus lists */ @@ -981,27 +918,13 @@ int __init device_driver_init(void) return error; } - /* initialise the garbage collection */ - pid = kernel_thread(device_cleanup_thread,NULL, - (CLONE_FS | CLONE_FILES | CLONE_SIGHAND)); - if (pid > 0) - kdeviced_pid = pid; - else { - DBG("DEV: Could not start cleanup thread\n"); - return pid; - } - DBG("DEV: Done Initialising\n"); return error; } void __exit device_driver_exit(void) { - if (kdeviced_pid) { - kill_proc(kdeviced_pid,SIGTERM,1); - kdeviced_pid = 0; - wait_for_completion(&kdeviced_exited); - } + } static int __init device_setup(char *str) diff --git a/mm/highmem.c b/mm/highmem.c index c353ab73123c..4d248a59c314 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -214,7 +214,7 @@ static inline void copy_to_high_bio_irq(struct bio *to, struct bio *from) struct bio_vec *tovec, *fromvec; int i; - bio_for_each_segment(tovec, to, i) { + __bio_for_each_segment(tovec, to, i, 0) { fromvec = &from->bi_io_vec[i]; /* @@ -225,12 +225,11 @@ static inline void copy_to_high_bio_irq(struct bio *to, struct bio *from) vfrom = page_address(fromvec->bv_page) + fromvec->bv_offset; - __save_flags(flags); - __cli(); + local_irq_save(flags); vto = kmap_atomic(tovec->bv_page, KM_BOUNCE_READ); - memcpy(vto + tovec->bv_offset, vfrom, to->bi_size); + memcpy(vto + tovec->bv_offset, vfrom, tovec->bv_len); kunmap_atomic(vto, KM_BOUNCE_READ); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -263,28 +262,39 @@ __initcall(init_emergency_pool); static inline int bounce_end_io (struct bio *bio, int nr_sectors) { struct bio *bio_orig = bio->bi_private; - struct page *page = bio_page(bio); + struct bio_vec *bvec, *org_vec; unsigned long flags; - int ret; + int ret, i; - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) - set_bit(BIO_UPTODATE, &bio_orig->bi_flags); + if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + goto out_eio; - ret = bio_orig->bi_end_io(bio_orig, nr_sectors); + set_bit(BIO_UPTODATE, &bio_orig->bi_flags); + /* + * free up bounce indirect pages used + */ spin_lock_irqsave(&emergency_lock, flags); - if (nr_emergency_pages >= POOL_SIZE) { - spin_unlock_irqrestore(&emergency_lock, flags); - __free_page(page); - } else { - /* - * We are abusing page->list to manage - * the highmem emergency pool: - */ - list_add(&page->list, &emergency_pages); - nr_emergency_pages++; - spin_unlock_irqrestore(&emergency_lock, flags); + __bio_for_each_segment(bvec, bio, i, 0) { + org_vec = &bio_orig->bi_io_vec[i]; + if (bvec->bv_page == org_vec->bv_page) + continue; + + if (nr_emergency_pages >= POOL_SIZE) + __free_page(bvec->bv_page); + else { + /* + * We are abusing page->list to manage + * the highmem emergency pool: + */ + list_add(&bvec->bv_page->list, &emergency_pages); + nr_emergency_pages++; + } } + spin_unlock_irqrestore(&emergency_lock, flags); + +out_eio: + ret = bio_orig->bi_end_io(bio_orig, nr_sectors); bio_put(bio); return ret; -- cgit v1.2.3