patch-1.3.69 linux/drivers/block/linear.c
Next file: linux/drivers/block/ll_rw_blk.c
Previous file: linux/drivers/block/README.md
Back to the patch index
Back to the overall index
- Lines: 242
- Date:
Mon Feb 26 13:51:45 1996
- Orig file:
v1.3.68/linux/drivers/block/linear.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v1.3.68/linux/drivers/block/linear.c linux/drivers/block/linear.c
@@ -0,0 +1,241 @@
+
+/*
+ linear.c : Multiple Devices driver for Linux
+ Copyright (C) 1994-96 Marc ZYNGIER
+ <zyngier@ufr-info-p7.ibp.fr> or
+ <maz@gloups.fdn.fr>
+
+ Linear mode management functions.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ You should have received a copy of the GNU General Public License
+ (for example /usr/src/linux/COPYING); if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+
+#include <linux/md.h>
+#include <linux/linear.h>
+#include <linux/malloc.h>
+
+#define MAJOR_NR MD_MAJOR
+#define MD_DRIVER
+#define MD_PERSONALITY
+
+#include <linux/blk.h>
+
+static int linear_run (int minor, struct md_dev *mddev)
+{
+ int cur=0, i, size, dev0_size, nb_zone;
+ struct linear_data *data;
+
+ MOD_INC_USE_COUNT;
+
+ mddev->private=kmalloc (sizeof (struct linear_data), GFP_KERNEL);
+ data=(struct linear_data *) mddev->private;
+
+ /*
+ Find out the smallest device. This was previously done
+ at registery time, but since it violates modularity,
+ I moved it here... Any comment ? ;-)
+ */
+
+ data->smallest=devices[minor];
+ for (i=1; i<mddev->nb_dev; i++)
+ if (data->smallest->size > devices[minor][i].size)
+ data->smallest=devices[minor]+i;
+
+ nb_zone=data->nr_zones=
+ md_size[minor]/data->smallest->size +
+ (md_size[minor]%data->smallest->size ? 1 : 0);
+
+ data->hash_table=kmalloc (sizeof (struct linear_hash)*nb_zone, GFP_KERNEL);
+
+ size=devices[minor][cur].size;
+
+ i=0;
+ while (cur<mddev->nb_dev)
+ {
+ data->hash_table[i].dev0=devices[minor]+cur;
+
+ if (size>=data->smallest->size) /* If we completly fill the slot */
+ {
+ data->hash_table[i++].dev1=NULL;
+ size-=data->smallest->size;
+
+ if (!size)
+ {
+ if (++cur==mddev->nb_dev) continue;
+ size=devices[minor][cur].size;
+ }
+
+ continue;
+ }
+
+ if (++cur==mddev->nb_dev) /* Last dev, set dev1 as NULL */
+ {
+ data->hash_table[i].dev1=NULL;
+ continue;
+ }
+
+ dev0_size=size; /* Here, we use a 2nd dev to fill the slot */
+ size=devices[minor][cur].size;
+ data->hash_table[i++].dev1=devices[minor]+cur;
+ size-=(data->smallest->size - dev0_size);
+ }
+
+ return 0;
+}
+
+static int linear_stop (int minor, struct md_dev *mddev)
+{
+ struct linear_data *data=(struct linear_data *) mddev->private;
+
+ kfree (data->hash_table);
+ kfree (data);
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+
+static int linear_map (int minor, struct md_dev *mddev, struct request *req)
+{
+ struct linear_data *data=(struct linear_data *) mddev->private;
+ struct linear_hash *hash;
+ struct real_dev *tmp_dev;
+ long block, rblock;
+ struct buffer_head *bh, *bh2;
+ int queue, nblk;
+ static struct request pending[MAX_REAL]={{0, }, };
+
+ while (req->nr_sectors)
+ {
+ block=req->sector >> 1;
+ hash=data->hash_table+(block/data->smallest->size);
+
+ if (block >= (hash->dev0->size + hash->dev0->offset))
+ {
+ if (!hash->dev1)
+ printk ("linear_map : hash->dev1==NULL for block %ld\n", block);
+ tmp_dev=hash->dev1;
+ }
+ else
+ tmp_dev=hash->dev0;
+
+ if (block >= (tmp_dev->size + tmp_dev->offset) || block < tmp_dev->offset)
+ printk ("Block %ld out of bounds on dev %04x size %d offset %d\n", block, tmp_dev->dev, tmp_dev->size, tmp_dev->offset);
+
+ rblock=(block-(tmp_dev->offset));
+
+ if (req->sem) /* This is a paging request */
+ {
+ req->rq_dev=tmp_dev->dev;
+ req->sector=rblock << 1;
+ add_request (blk_dev+MAJOR (tmp_dev->dev), req);
+
+ return REDIRECTED_REQ;
+ }
+
+ queue=tmp_dev - devices[minor];
+
+ for (nblk=0, bh=bh2=req->bh;
+ bh && rblock + nblk + (bh->b_size >> 10) <= tmp_dev->size;
+ nblk+=bh->b_size >> 10, bh2=bh, bh=bh->b_reqnext)
+ {
+ if (!buffer_locked(bh))
+ printk("md%d: block %ld not locked\n", minor, bh->b_blocknr);
+
+ bh->b_rdev=tmp_dev->dev;
+ }
+
+ pending[queue].rq_dev=tmp_dev->dev;
+ pending[queue].cmd=req->cmd;
+ pending[queue].sector=rblock << 1;
+ pending[queue].nr_sectors=nblk << 1;
+ pending[queue].current_nr_sectors=req->bh->b_size >> 9;
+ pending[queue].bh=req->bh;
+ pending[queue].bhtail=bh2;
+ bh2->b_reqnext=NULL;
+
+ req->bh=bh;
+ req->sector+=nblk << 1;
+ req->nr_sectors-=nblk << 1;
+ }
+
+ req->rq_status=RQ_INACTIVE;
+ wake_up (&wait_for_request);
+ make_md_request (pending, mddev->nb_dev);
+ return REDIRECTED_REQ;
+}
+
+
+static int linear_status (char *page, int minor, struct md_dev *mddev)
+{
+ int sz=0;
+
+#undef MD_DEBUG
+#ifdef MD_DEBUG
+ int j;
+ struct linear_data *data=(struct linear_data *) mddev->private;
+
+ sz+=sprintf (page+sz, " ");
+ for (j=0; j<data->nr_zones; j++)
+ {
+ sz+=sprintf (page+sz, "[%s",
+ partition_name (data->hash_table[j].dev0->dev));
+
+ if (data->hash_table[j].dev1)
+ sz+=sprintf (page+sz, "/%s] ",
+ partition_name(data->hash_table[j].dev1->dev));
+ else
+ sz+=sprintf (page+sz, "] ");
+ }
+
+ sz+=sprintf (page+sz, "\n");
+#endif
+ return sz;
+}
+
+
+static struct md_personality linear_personality=
+{
+ "linear",
+ linear_map,
+ linear_run,
+ linear_stop,
+ linear_status,
+ NULL, /* no ioctls */
+ 0
+};
+
+
+#ifndef MODULE
+
+void linear_init (void)
+{
+ register_md_personality (LINEAR, &linear_personality);
+}
+
+#else
+
+int init_module (void)
+{
+ return (register_md_personality (LINEAR, &linear_personality));
+}
+
+void cleanup_module (void)
+{
+ if (MOD_IN_USE)
+ printk ("md linear : module still busy...\n");
+ else
+ unregister_md_personality (LINEAR);
+}
+
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this