diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2009-11-08 14:54:08 +0200 |
---|---|---|
committer | Boaz Harrosh <bharrosh@panasas.com> | 2009-12-10 09:59:22 +0200 |
commit | 06886a5a3dc5a5abe0a4d257c26317bde7047be8 (patch) | |
tree | 858ac56e120c0473d764fc64a2660e6d79729c8c /fs/exofs/ios.c | |
parent | 8ce9bdd1fbe962933736d7977e972972cd5d754c (diff) | |
download | lwn-06886a5a3dc5a5abe0a4d257c26317bde7047be8.tar.gz lwn-06886a5a3dc5a5abe0a4d257c26317bde7047be8.zip |
exofs: Move all operations to an io_engine
In anticipation for multi-device operations, we separate osd operations
into an abstract I/O API. Currently only one device is used but later
when adding more devices, we will drive all devices in parallel according
to a "data_map" that describes how data is arranged on multiple devices.
The file system level operates, like before, as if there is one object
(inode-number) and an i_size. The io engine will split this to the same
object-number but on multiple device.
At first we introduce Mirror (raid 1) layout. But at the final outcome
we intend to fully implement the pNFS-Objects data-map, including
raid 0,4,5,6 over mirrored devices, over multiple device-groups. And
more. See: http://tools.ietf.org/html/draft-ietf-nfsv4-pnfs-obj-12
* Define an io_state based API for accessing osd storage devices
in an abstract way.
Usage:
First a caller allocates an io state with:
exofs_get_io_state(struct exofs_sb_info *sbi,
struct exofs_io_state** ios);
Then calles one of:
exofs_sbi_create(struct exofs_io_state *ios);
exofs_sbi_remove(struct exofs_io_state *ios);
exofs_sbi_write(struct exofs_io_state *ios);
exofs_sbi_read(struct exofs_io_state *ios);
exofs_oi_truncate(struct exofs_i_info *oi, u64 new_len);
And when done
exofs_put_io_state(struct exofs_io_state *ios);
* Convert all source files to use this new API
* Convert from bio_alloc to bio_kmalloc
* In io engine we make use of the now fixed osd_req_decode_sense
There are no functional changes or on disk additions after this patch.
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Diffstat (limited to 'fs/exofs/ios.c')
-rw-r--r-- | fs/exofs/ios.c | 386 |
1 files changed, 333 insertions, 53 deletions
diff --git a/fs/exofs/ios.c b/fs/exofs/ios.c index 4372542df284..bb2f9d341fdf 100644 --- a/fs/exofs/ios.c +++ b/fs/exofs/ios.c @@ -23,88 +23,327 @@ */ #include <scsi/scsi_device.h> -#include <scsi/osd_sense.h> #include "exofs.h" -int exofs_check_ok_resid(struct osd_request *or, u64 *in_resid, u64 *out_resid) +void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], const struct osd_obj_id *obj) { - struct osd_sense_info osi; - int ret = osd_req_decode_sense(or, &osi); - - if (ret) { /* translate to Linux codes */ - if (osi.additional_code == scsi_invalid_field_in_cdb) { - if (osi.cdb_field_offset == OSD_CFO_STARTING_BYTE) - ret = -EFAULT; - if (osi.cdb_field_offset == OSD_CFO_OBJECT_ID) - ret = -ENOENT; - else - ret = -EINVAL; - } else if (osi.additional_code == osd_quota_error) - ret = -ENOSPC; - else - ret = -EIO; + osd_sec_init_nosec_doall_caps(cred_a, obj, false, true); +} + +int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj, + u64 offset, void *p, unsigned length) +{ + struct osd_request *or = osd_start_request(od, GFP_KERNEL); +/* struct osd_sense_info osi = {.key = 0};*/ + int ret; + + if (unlikely(!or)) { + EXOFS_DBGMSG("%s: osd_start_request failed.\n", __func__); + return -ENOMEM; + } + ret = osd_req_read_kern(or, obj, offset, p, length); + if (unlikely(ret)) { + EXOFS_DBGMSG("%s: osd_req_read_kern failed.\n", __func__); + goto out; } - /* FIXME: should be include in osd_sense_info */ - if (in_resid) - *in_resid = or->in.req ? or->in.req->resid_len : 0; + ret = osd_finalize_request(or, 0, cred, NULL); + if (unlikely(ret)) { + EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret); + goto out; + } - if (out_resid) - *out_resid = or->out.req ? or->out.req->resid_len : 0; + ret = osd_execute_request(or); + if (unlikely(ret)) + EXOFS_DBGMSG("osd_execute_request() => %d\n", ret); + /* osd_req_decode_sense(or, ret); */ +out: + osd_end_request(or); return ret; } -void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], const struct osd_obj_id *obj) +int exofs_get_io_state(struct exofs_sb_info *sbi, struct exofs_io_state** pios) { - osd_sec_init_nosec_doall_caps(cred_a, obj, false, true); + struct exofs_io_state *ios; + + /*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); + if (unlikely(!ios)) { + *pios = NULL; + return -ENOMEM; + } + + ios->sbi = sbi; + ios->obj.partition = sbi->s_pid; + *pios = ios; + return 0; } -/* - * Perform a synchronous OSD operation. - */ -int exofs_sync_op(struct osd_request *or, int timeout, uint8_t *credential) +void exofs_put_io_state(struct exofs_io_state *ios) { - int ret; + if (ios) { + unsigned i; - or->timeout = timeout; - ret = osd_finalize_request(or, 0, credential, NULL); - if (ret) { - EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret); - return ret; + for (i = 0; i < ios->numdevs; i++) { + struct exofs_per_dev_state *per_dev = &ios->per_dev[i]; + + if (per_dev->or) + osd_end_request(per_dev->or); + if (per_dev->bio) + bio_put(per_dev->bio); + } + + kfree(ios); } +} - ret = osd_execute_request(or); +static void _sync_done(struct exofs_io_state *ios, void *p) +{ + struct completion *waiting = p; - if (ret) - EXOFS_DBGMSG("osd_execute_request() => %d\n", ret); - /* osd_req_decode_sense(or, ret); */ + complete(waiting); +} + +static void _last_io(struct kref *kref) +{ + struct exofs_io_state *ios = container_of( + kref, struct exofs_io_state, kref); + + ios->done(ios, ios->private); +} + +static void _done_io(struct osd_request *or, void *p) +{ + struct exofs_io_state *ios = p; + + kref_put(&ios->kref, _last_io); +} + +static int exofs_io_execute(struct exofs_io_state *ios) +{ + DECLARE_COMPLETION_ONSTACK(wait); + bool sync = (ios->done == NULL); + int i, ret; + + if (sync) { + ios->done = _sync_done; + ios->private = &wait; + } + + for (i = 0; i < ios->numdevs; i++) { + struct osd_request *or = ios->per_dev[i].or; + if (unlikely(!or)) + continue; + + ret = osd_finalize_request(or, 0, ios->cred, NULL); + if (unlikely(ret)) { + EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", + ret); + return ret; + } + } + + kref_init(&ios->kref); + + for (i = 0; i < ios->numdevs; i++) { + struct osd_request *or = ios->per_dev[i].or; + if (unlikely(!or)) + continue; + + kref_get(&ios->kref); + osd_execute_request_async(or, _done_io, ios); + } + + kref_put(&ios->kref, _last_io); + ret = 0; + + if (sync) { + wait_for_completion(&wait); + ret = exofs_check_io(ios, NULL); + } return ret; } -/* - * Perform an asynchronous OSD operation. - */ -int exofs_async_op(struct osd_request *or, osd_req_done_fn *async_done, - void *caller_context, u8 *cred) +int exofs_check_io(struct exofs_io_state *ios, u64 *resid) { - int ret; + enum osd_err_priority acumulated_osd_err = 0; + int acumulated_lin_err = 0; + int i; - ret = osd_finalize_request(or, 0, cred, NULL); - if (ret) { - EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret); - return ret; + for (i = 0; i < ios->numdevs; i++) { + struct osd_sense_info osi; + int ret = osd_req_decode_sense(ios->per_dev[i].or, &osi); + + if (likely(!ret)) + continue; + + if (unlikely(ret == -EFAULT)) { + EXOFS_DBGMSG("%s: EFAULT Need page clear\n", __func__); + /*FIXME: All the pages in this device range should: + * clear_highpage(page); + */ + } + + if (osi.osd_err_pri >= acumulated_osd_err) { + acumulated_osd_err = osi.osd_err_pri; + acumulated_lin_err = ret; + } + } + + /* TODO: raid specific residual calculations */ + if (resid) { + if (likely(!acumulated_lin_err)) + *resid = 0; + else + *resid = ios->length; + } + + return acumulated_lin_err; +} + +int exofs_sbi_create(struct exofs_io_state *ios) +{ + int i, ret; + + for (i = 0; i < 1; i++) { + struct osd_request *or; + + or = osd_start_request(ios->sbi->s_dev, GFP_KERNEL); + if (unlikely(!or)) { + EXOFS_ERR("%s: osd_start_request failed\n", __func__); + ret = -ENOMEM; + goto out; + } + ios->per_dev[i].or = or; + ios->numdevs++; + + osd_req_create_object(or, &ios->obj); + } + ret = exofs_io_execute(ios); + +out: + return ret; +} + +int exofs_sbi_remove(struct exofs_io_state *ios) +{ + int i, ret; + + for (i = 0; i < 1; i++) { + struct osd_request *or; + + or = osd_start_request(ios->sbi->s_dev, GFP_KERNEL); + if (unlikely(!or)) { + EXOFS_ERR("%s: osd_start_request failed\n", __func__); + ret = -ENOMEM; + goto out; + } + ios->per_dev[i].or = or; + ios->numdevs++; + + osd_req_remove_object(or, &ios->obj); + } + ret = exofs_io_execute(ios); + +out: + return ret; +} + +int exofs_sbi_write(struct exofs_io_state *ios) +{ + int i, ret; + + for (i = 0; i < 1; i++) { + struct osd_request *or; + + or = osd_start_request(ios->sbi->s_dev, GFP_KERNEL); + if (unlikely(!or)) { + EXOFS_ERR("%s: osd_start_request failed\n", __func__); + ret = -ENOMEM; + goto out; + } + ios->per_dev[i].or = or; + ios->numdevs++; + + if (ios->bio) { + struct bio *bio; + + bio = ios->bio; + + osd_req_write(or, &ios->obj, ios->offset, bio, + ios->length); +/* EXOFS_DBGMSG("write sync=%d\n", sync);*/ + } else if (ios->kern_buff) { + osd_req_write_kern(or, &ios->obj, ios->offset, + ios->kern_buff, ios->length); +/* EXOFS_DBGMSG("write_kern sync=%d\n", sync);*/ + } else { + osd_req_set_attributes(or, &ios->obj); +/* EXOFS_DBGMSG("set_attributes sync=%d\n", sync);*/ + } + + if (ios->out_attr) + osd_req_add_set_attr_list(or, ios->out_attr, + ios->out_attr_len); + + if (ios->in_attr) + osd_req_add_get_attr_list(or, ios->in_attr, + ios->in_attr_len); } + ret = exofs_io_execute(ios); + +out: + return ret; +} + +int exofs_sbi_read(struct exofs_io_state *ios) +{ + int i, ret; + + for (i = 0; i < 1; i++) { + struct osd_request *or; + + or = osd_start_request(ios->sbi->s_dev, GFP_KERNEL); + if (unlikely(!or)) { + EXOFS_ERR("%s: osd_start_request failed\n", __func__); + ret = -ENOMEM; + goto out; + } + ios->per_dev[i].or = or; + ios->numdevs++; + + if (ios->bio) { + osd_req_read(or, &ios->obj, ios->offset, ios->bio, + ios->length); +/* EXOFS_DBGMSG("read sync=%d\n", sync);*/ + } else if (ios->kern_buff) { + osd_req_read_kern(or, &ios->obj, ios->offset, + ios->kern_buff, ios->length); +/* EXOFS_DBGMSG("read_kern sync=%d\n", sync);*/ + } else { + osd_req_get_attributes(or, &ios->obj); +/* EXOFS_DBGMSG("get_attributes sync=%d\n", sync);*/ + } + + if (ios->out_attr) + osd_req_add_set_attr_list(or, ios->out_attr, + ios->out_attr_len); - ret = osd_execute_request_async(or, async_done, caller_context); + if (ios->in_attr) + osd_req_add_get_attr_list(or, ios->in_attr, + ios->in_attr_len); + } + ret = exofs_io_execute(ios); - if (ret) - EXOFS_DBGMSG("osd_execute_request_async() => %d\n", ret); +out: return ret; } -int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr) +int extract_attr_from_ios(struct exofs_io_state *ios, struct osd_attr *attr) { struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */ void *iter = NULL; @@ -112,7 +351,8 @@ int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr) do { nelem = 1; - osd_req_decode_get_attr_list(or, &cur_attr, &nelem, &iter); + osd_req_decode_get_attr_list(ios->per_dev[0].or, + &cur_attr, &nelem, &iter); if ((cur_attr.attr_page == attr->attr_page) && (cur_attr.attr_id == attr->attr_id)) { attr->len = cur_attr.len; @@ -123,3 +363,43 @@ int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr) return -EIO; } + +int exofs_oi_truncate(struct exofs_i_info *oi, u64 size) +{ + struct exofs_sb_info *sbi = oi->vfs_inode.i_sb->s_fs_info; + struct exofs_io_state *ios; + struct osd_attr attr; + __be64 newsize; + int i, ret; + + if (exofs_get_io_state(sbi, &ios)) + return -ENOMEM; + + ios->obj.id = exofs_oi_objno(oi); + ios->cred = oi->i_cred; + + newsize = cpu_to_be64(size); + attr = g_attr_logical_length; + attr.val_ptr = &newsize; + + for (i = 0; i < 1; i++) { + struct osd_request *or; + + or = osd_start_request(sbi->s_dev, GFP_KERNEL); + if (unlikely(!or)) { + EXOFS_ERR("%s: osd_start_request failed\n", __func__); + ret = -ENOMEM; + goto out; + } + ios->per_dev[i].or = or; + ios->numdevs++; + + osd_req_set_attributes(or, &ios->obj); + osd_req_add_set_attr_list(or, &attr, 1); + } + ret = exofs_io_execute(ios); + +out: + exofs_put_io_state(ios); + return ret; +} |