rather than requested size.
b=11737
i=green
i=shadow
Details : size of struct ll_inode_info is to big for union inode.u and this
can be cause of random memory corruption.
+Severity : normal
+Bugzilla : 11737
+Description: Short directio read returns full requested size rather than
+ actual amount read.
+Details : Direct I/O operations should return actual amount of bytes
+ transferred rather than requested size.
+
--------------------------------------------------------------------------------
2007-05-03 Cluster File Systems, Inc. <info@clusterfs.com>
struct list_head set_requests;
set_interpreter_func set_interpret; /* completion callback */
void *set_arg; /* completion context */
+ void *set_countp; /* pointer to NOB counter in case
+ * of directIO (bug11737) */
/* locked so that any old caller can communicate requests to
* the set holder who can then fold them into the lock-free set */
spinlock_t set_new_req_lock;
{
struct ptlrpc_request_set *set = NULL;
struct obd_info oinfo = { { { 0 } } };
+ atomic_t nob;
int rc = 0;
ENTRY;
set = ptlrpc_prep_set();
if (set == NULL)
RETURN(-ENOMEM);
+ atomic_set(&nob, 0);
+ set->set_countp = &nob;
oinfo.oi_oa = oa;
oinfo.oi_md = lsm;
rc = ptlrpc_set_wait(set);
if (rc)
CERROR("error from callback: rc = %d\n", rc);
+ else
+ rc = atomic_read(&nob);
} else {
CDEBUG(rc == -ENOSPC ? D_INODE : D_ERROR,
"error from obd_brw_async: rc = %d\n", rc);
struct brw_page *pga;
struct obdo oa;
int length, i, flags, rc = 0;
- loff_t offset;
+ loff_t offset, offset_orig;
ENTRY;
if (!lsm || !lsm->lsm_object_id)
RETURN(-EBADF);
offset = ((obd_off)blocknr << inode->i_blkbits);
+ offset_orig = offset;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), size="LPSZ
", offset=%lld=%llx, pages %u\n",
inode->i_ino, inode->i_generation, inode, iobuf->length,
LPROC_LL_DIRECT_READ, iobuf->length);
rc = obd_brw_rqset(rw, ll_i2obdexp(inode), &oa, lsm, iobuf->nr_pages,
pga, NULL);
- if (rc == 0) {
- rc = iobuf->length;
- if (rw == OBD_BRW_WRITE) {
- lov_stripe_lock(lsm);
- obd_adjust_kms(ll_i2obdexp(inode), lsm, offset, 0);
- lov_stripe_unlock(lsm);
- }
+ if ((rc > 0) && (rw == OBD_BRW_WRITE)) {
+ lov_stripe_lock(lsm);
+ obd_adjust_kms(ll_i2obdexp(inode), lsm, offset_orig + rc, 0);
+ lov_stripe_unlock(lsm);
}
OBD_FREE(pga, sizeof(*pga) * iobuf->nr_pages);
struct obdo oa;
int i, rc = 0;
size_t length;
+ loff_t file_offset_orig = file_offset;
ENTRY;
OBD_ALLOC(pga, sizeof(*pga) * page_count);
rc = obd_brw_rqset(rw == WRITE ? OBD_BRW_WRITE : OBD_BRW_READ,
ll_i2obdexp(inode), &oa, lsm, page_count, pga, NULL);
- if (rc == 0) {
- rc = size;
- if (rw == WRITE) {
- lov_stripe_lock(lsm);
- obd_adjust_kms(ll_i2obdexp(inode), lsm, file_offset, 0);
- lov_stripe_unlock(lsm);
- }
+ if ((rc > 0) && (rw == WRITE)) {
+ lov_stripe_lock(lsm);
+ obd_adjust_kms(ll_i2obdexp(inode), lsm, file_offset_orig + rc, 0);
+ lov_stripe_unlock(lsm);
}
OBD_FREE(pga, sizeof(*pga) * page_count);
if (rc < 0)
RETURN(rc);
+ if (req->rq_set && req->rq_set->set_countp)
+ atomic_add(rc, (atomic_t *)req->rq_set->set_countp);
+
if (unlikely(aa->aa_oa->o_valid & OBD_MD_FLCKSUM))
client_cksum = aa->aa_oa->o_cksum; /* save for later */
rc = read(fd, rbuf, len);
if (rc != len) {
- printf("Read error: %s (rc = %d)\n",strerror(errno),rc);
+ printf("Read error: %s rc = %d\n",strerror(errno),rc);
return 1;
}
}
run_test 118 "verify O_SYNC work"
+test_119() # bug 11737
+{
+ dd if=/dev/zero of=$DIR/$tfile bs=4k count=2
+ sync
+ # we ask to read 3 blocks -- more than a file size
+ NOB=`directio read $DIR/$tfile 0 3 | awk '/error/ {print $6}'`
+ # check if we have read num of bytes not equal to file size (8k)
+ if [ "$NOB" != "8192" ]; then
+ error "read $NOB bytes instead of 8192"
+ fi
+ rm -f $DIR/$tfile
+}
+run_test 119 "Short directIO read must return actual read amount"
+
TMPDIR=$OLDTMPDIR
TMP=$OLDTMP
HOME=$OLDHOME