From 04dc1e88ad9c9f9639019e9646a89ce0ebf706bb Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Mon, 16 Nov 2009 16:03:05 +0200 Subject: exofs: Multi-device mirror support This patch changes on-disk format, it is accompanied with a parallel patch to mkfs.exofs that enables multi-device capabilities. After this patch, old exofs will refuse to mount a new formatted FS and new exofs will refuse an old format. This is done by moving the magic field offset inside the FSCB. A new FSCB *version* field was added. In the future, exofs will refuse to mount unmatched FSCB version. To up-grade or down-grade an exofs one must use mkfs.exofs --upgrade option before mounting. Introduced, a new object that contains a *device-table*. This object contains the default *data-map* and a linear array of devices information, which identifies the devices used in the filesystem. This object is only written to offline by mkfs.exofs. This is why it is kept separate from the FSCB, since the later is written to while mounted. Same partition number, same object number is used on all devices only the device varies. * define the new format, then load the device table on mount time make sure every thing is supported. * Change I/O engine to now support Mirror IO, .i.e write same data to multiple devices, read from a random device to spread the read-load from multiple clients (TODO: stripe read) Implementation notes: A few points introduced in previous patch should be mentioned here: * Special care was made so absolutlly all operation that have any chance of failing are done before any osd-request is executed. This is to minimize the need for a data consistency recovery, to only real IO errors. * Each IO state has a kref. It starts at 1, any osd-request executed will increment the kref, finally when all are executed the first ref is dropped. At IO-done, each request completion decrements the kref, the last one to return executes the internal _last_io() routine. _last_io() will call the registered io_state_done. On sync mode a caller does not supply a done method, indicating a synchronous request, the caller is put to sleep and a special io_state_done is registered that will awaken the caller. Though also in sync mode all operations are executed in parallel. Signed-off-by: Boaz Harrosh --- fs/exofs/ios.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'fs/exofs/ios.c') diff --git a/fs/exofs/ios.c b/fs/exofs/ios.c index bb2f9d341fd..5bad01fa1f9 100644 --- a/fs/exofs/ios.c +++ b/fs/exofs/ios.c @@ -71,7 +71,7 @@ int exofs_get_io_state(struct exofs_sb_info *sbi, struct exofs_io_state** pios) /*TODO: Maybe use kmem_cach per sbi of size * exofs_io_state_size(sbi->s_numdevs) */ - ios = kzalloc(exofs_io_state_size(1), GFP_KERNEL); + ios = kzalloc(exofs_io_state_size(sbi->s_numdevs), GFP_KERNEL); if (unlikely(!ios)) { *pios = NULL; return -ENOMEM; @@ -209,10 +209,10 @@ int exofs_sbi_create(struct exofs_io_state *ios) { int i, ret; - for (i = 0; i < 1; i++) { + for (i = 0; i < ios->sbi->s_numdevs; i++) { struct osd_request *or; - or = osd_start_request(ios->sbi->s_dev, GFP_KERNEL); + or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL); if (unlikely(!or)) { EXOFS_ERR("%s: osd_start_request failed\n", __func__); ret = -ENOMEM; @@ -233,10 +233,10 @@ int exofs_sbi_remove(struct exofs_io_state *ios) { int i, ret; - for (i = 0; i < 1; i++) { + for (i = 0; i < ios->sbi->s_numdevs; i++) { struct osd_request *or; - or = osd_start_request(ios->sbi->s_dev, GFP_KERNEL); + or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL); if (unlikely(!or)) { EXOFS_ERR("%s: osd_start_request failed\n", __func__); ret = -ENOMEM; @@ -257,10 +257,10 @@ int exofs_sbi_write(struct exofs_io_state *ios) { int i, ret; - for (i = 0; i < 1; i++) { + for (i = 0; i < ios->sbi->s_numdevs; i++) { struct osd_request *or; - or = osd_start_request(ios->sbi->s_dev, GFP_KERNEL); + or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL); if (unlikely(!or)) { EXOFS_ERR("%s: osd_start_request failed\n", __func__); ret = -ENOMEM; @@ -272,7 +272,21 @@ int exofs_sbi_write(struct exofs_io_state *ios) if (ios->bio) { struct bio *bio; - bio = ios->bio; + if (i != 0) { + bio = bio_kmalloc(GFP_KERNEL, + ios->bio->bi_max_vecs); + if (unlikely(!bio)) { + ret = -ENOMEM; + goto out; + } + + __bio_clone(bio, ios->bio); + bio->bi_bdev = NULL; + bio->bi_next = NULL; + ios->per_dev[i].bio = bio; + } else { + bio = ios->bio; + } osd_req_write(or, &ios->obj, ios->offset, bio, ios->length); @@ -306,8 +320,10 @@ int exofs_sbi_read(struct exofs_io_state *ios) for (i = 0; i < 1; i++) { struct osd_request *or; + unsigned first_dev = (unsigned)ios->obj.id; - or = osd_start_request(ios->sbi->s_dev, GFP_KERNEL); + first_dev %= ios->sbi->s_numdevs; + or = osd_start_request(ios->sbi->s_ods[first_dev], GFP_KERNEL); if (unlikely(!or)) { EXOFS_ERR("%s: osd_start_request failed\n", __func__); ret = -ENOMEM; @@ -382,10 +398,10 @@ int exofs_oi_truncate(struct exofs_i_info *oi, u64 size) attr = g_attr_logical_length; attr.val_ptr = &newsize; - for (i = 0; i < 1; i++) { + for (i = 0; i < sbi->s_numdevs; i++) { struct osd_request *or; - or = osd_start_request(sbi->s_dev, GFP_KERNEL); + or = osd_start_request(sbi->s_ods[i], GFP_KERNEL); if (unlikely(!or)) { EXOFS_ERR("%s: osd_start_request failed\n", __func__); ret = -ENOMEM; -- cgit v1.2.3