rather than requested size.
b=11737
i=adilger
i=shadow
Details : A lock's skiplist need to be cleanup when it being unlinked
from its resource list.
+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,
ll_stats_ops_tally(ll_i2sbi(inode), 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);
{
struct osc_brw_async_args *aa = data;
int i;
+ int nob = rc;
ENTRY;
rc = osc_brw_fini_request(request, rc);
if (rc == 0)
RETURN(0);
}
+ if ((rc >= 0) && request->rq_set && request->rq_set->set_countp)
+ atomic_add(nob, (atomic_t *)request->rq_set->set_countp);
spin_lock(&aa->aa_cli->cl_loi_list_lock);
for (i = 0; i < aa->aa_page_count; i++)
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;
}
unset F77_TMP
test_78() { # bug 10901
+ NSEQ=5
F78SIZE=$(($(awk '/MemFree:/ { print $2 }' /proc/meminfo) / 1024))
[ $F78SIZE -gt 512 ] && F78SIZE=512
[ $F78SIZE -gt $((MAXFREE / 1024)) ] && F78SIZE=$((MAXFREE / 1024))
[ $F78SIZE -gt $((SMALLESTOST * $OSTCOUNT / 1024)) ] && \
F78SIZE=$((SMALLESTOST * $OSTCOUNT / 1024))
$SETSTRIPE $DIR/$tfile 0 -1 -1 || error "setstripe failed"
- $DIRECTIO rdwr $DIR/$tfile 0 $F78SIZE 1048576 || error "rdwr failed"
+ for i in `seq 1 $NSEQ`
+ do
+ echo directIO rdwr round $i of $NSEQ
+ $DIRECTIO rdwr $DIR/$tfile 0 $F78SIZE 1048576 || error "rdwr failed"
+ done
rm -f $DIR/$tfile
}
}
run_test 118 "verify O_SYNC work"
+test_119a() # bug 11737
+{
+ BSIZE=$((512 * 1024))
+ directio write $DIR/$tfile 0 1 $BSIZE
+ # We ask to read two blocks, which is more than a file size.
+ # directio will indicate an error when requested and actual
+ # sizes aren't equeal (a normal situation in this case) and
+ # print actual read amount.
+ NOB=`directio read $DIR/$tfile 0 2 $BSIZE | awk '/error/ {print $6}'`
+ if [ "$NOB" != "$BSIZE" ]; then
+ error "read $NOB bytes instead of $BSIZE"
+ fi
+ rm -f $DIR/$tfile
+}
+run_test 119a "Short directIO read must return actual read amount"
+
+test_119b() # bug 11737
+{
+ [ "$OSTCOUNT" -lt "2" ] && echo "skipping 2-stripe test" && return
+
+ lfs setstripe $DIR/$tfile 0 -1 2
+ dd if=/dev/zero of=$DIR/$tfile bs=1M count=1 seek=1 || error "dd failed"
+ sync
+ multiop $DIR/$tfile oO_RDONLY:O_DIRECT:r$((2048 * 1024)) || \
+ error "direct read failed"
+}
+run_test 119b "Sparse directIO read must return actual read amount"
+
TMPDIR=$OLDTMPDIR
TMP=$OLDTMP
HOME=$OLDHOME