so that each OSD can check for lnb array overflow.
the patch isn't final - there will be proper
implementation in osd-zfs and a new test.
Signed-off-by: Alex Zhuravlev <bzzz@whamcloud.com>
Change-Id: I43683c84e48006b4075f9a8b3e87cdfeae28c02b
Reviewed-on: https://review.whamcloud.com/35801
Reviewed-by: Mike Pershin <mpershin@whamcloud.com>
Reviewed-by: Lai Siyao <lai.siyao@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
* \param[in] pos position in the object to start
* \param[in] len size of region in bytes
* \param[out] lb array of descriptors to fill
+ * \param[in] maxlnb max slots in @lnb array
* \param[in] rw 0 if used to read, 1 if used for write
*
* \retval positive number of descriptors on success
loff_t pos,
ssize_t len,
struct niobuf_local *lb,
+ int maxlnb,
enum dt_bufs_type rw);
/**
static inline int dt_bufs_get(const struct lu_env *env, struct dt_object *d,
struct niobuf_remote *rnb,
- struct niobuf_local *lnb, enum dt_bufs_type rw)
+ struct niobuf_local *lnb, int maxlnb,
+ enum dt_bufs_type rw)
{
LASSERT(d);
LASSERT(d->do_body_ops);
LASSERT(d->do_body_ops->dbo_bufs_get);
return d->do_body_ops->dbo_bufs_get(env, d, rnb->rnb_offset,
- rnb->rnb_len, lnb, rw);
+ rnb->rnb_len, lnb, maxlnb, rw);
}
static inline int dt_bufs_put(const struct lu_env *env, struct dt_object *d,
#define OBD_FAIL_OST_DISCONNECT_DELAY 0x245
#define OBD_FAIL_OST_DELAY_TRANS 0x246
#define OBD_FAIL_OST_PREPARE_DELAY 0x247
+#define OBD_FAIL_OST_2BIG_NIOBUF 0x248
#define OBD_FAIL_LDLM 0x300
#define OBD_FAIL_LDLM_NAMESPACE_NEW 0x301
{
struct dt_object *dob;
int i, j, rc, tot_bytes = 0;
+ int maxlnb = *nr_local;
int level;
ENTRY;
dob = mdt_obj2dt(mo);
/* parse remote buffers to local buffers and prepare the latter */
for (i = 0, j = 0; i < niocount; i++) {
- rc = dt_bufs_get(env, dob, rnb + i, lnb + j, 0);
+ rc = dt_bufs_get(env, dob, rnb + i, lnb + j, maxlnb, 0);
if (unlikely(rc < 0))
GOTO(buf_put, rc);
/* correct index for local buffers to continue with */
j += rc;
+ maxlnb -= rc;
*nr_local += rc;
tot_bytes += rnb[i].rnb_len;
}
{
struct dt_object *dob;
int i, j, k, rc = 0, tot_bytes = 0;
+ int maxlnb = *nr_local;
ENTRY;
dob = mdt_obj2dt(mo);
/* parse remote buffers to local buffers and prepare the latter */
for (i = 0, j = 0; i < obj->ioo_bufcnt; i++) {
- rc = dt_bufs_get(env, dob, rnb + i, lnb + j, 1);
+ rc = dt_bufs_get(env, dob, rnb + i, lnb + j, maxlnb, 1);
if (unlikely(rc < 0))
GOTO(err, rc);
/* correct index for local buffers to continue with */
lnb[j + k].lnb_rc = -ENOSPC;
}
j += rc;
+ maxlnb -= rc;
*nr_local += rc;
tot_bytes += rnb[i].rnb_len;
}
if (lnb == NULL)
GOTO(unlock, rc = -ENOMEM);
- rc = dt_bufs_get(env, mo, rnb, lnb, 0);
+ rc = dt_bufs_get(env, mo, rnb, lnb, lnbs, 0);
if (unlikely(rc < 0))
GOTO(free, rc);
LASSERT(rc <= lnbs);
PTLRPC_MAX_BRW_PAGES;
rnb.rnb_offset = start_index << PAGE_SHIFT;
rnb.rnb_len = nr_local << PAGE_SHIFT;
- rc = dt_bufs_get(env, ofd_object_child(fo), &rnb, lnb, dbt);
+ rc = dt_bufs_get(env, ofd_object_child(fo), &rnb, lnb,
+ PTLRPC_MAX_BRW_PAGES, dbt);
if (unlikely(rc < 0))
break;
nr_local = rc;
struct ofd_object *fo;
int i, j, rc, tot_bytes = 0;
enum dt_bufs_type dbt = DT_BUFS_TYPE_READ;
+ int maxlnb = *nr_local;
ENTRY;
LASSERT(env != NULL);
dbt |= DT_BUFS_TYPE_LOCAL;
for (*nr_local = 0, i = 0, j = 0; i < niocount; i++) {
+
+ if (OBD_FAIL_CHECK(OBD_FAIL_OST_2BIG_NIOBUF))
+ rnb[i].rnb_len = 100 * 1024 * 1024;
+
rc = dt_bufs_get(env, ofd_object_child(fo), rnb + i,
- lnb + j, dbt);
+ lnb + j, maxlnb, dbt);
if (unlikely(rc < 0))
GOTO(buf_put, rc);
LASSERT(rc <= PTLRPC_MAX_BRW_PAGES);
/* correct index for local buffers to continue with */
j += rc;
*nr_local += rc;
+ maxlnb -= rc;
LASSERT(j <= PTLRPC_MAX_BRW_PAGES);
tot_bytes += rnb[i].rnb_len;
}
struct ofd_object *fo;
int i, j, k, rc = 0, tot_bytes = 0;
enum dt_bufs_type dbt = DT_BUFS_TYPE_WRITE;
+ int maxlnb = *nr_local;
ENTRY;
LASSERT(env != NULL);
/* parse remote buffers to local buffers and prepare the latter */
for (*nr_local = 0, i = 0, j = 0; i < obj->ioo_bufcnt; i++) {
+ if (OBD_FAIL_CHECK(OBD_FAIL_OST_2BIG_NIOBUF))
+ rnb[i].rnb_len += PAGE_SIZE;
rc = dt_bufs_get(env, ofd_object_child(fo),
- rnb + i, lnb + j, dbt);
+ rnb + i, lnb + j, maxlnb, dbt);
if (unlikely(rc < 0))
GOTO(err, rc);
LASSERT(rc <= PTLRPC_MAX_BRW_PAGES);
}
j += rc;
*nr_local += rc;
+ maxlnb -= rc;
LASSERT(j <= PTLRPC_MAX_BRW_PAGES);
tot_bytes += rnb[i].rnb_len;
}
}
static int osd_map_remote_to_local(loff_t offset, ssize_t len, int *nrpages,
- struct niobuf_local *lnb)
+ struct niobuf_local *lnb, int maxlnb)
{
+ int rc = 0;
ENTRY;
*nrpages = 0;
int poff = offset & (PAGE_SIZE - 1);
int plen = PAGE_SIZE - poff;
+ if (*nrpages >= maxlnb) {
+ rc = -EOVERFLOW;
+ break;
+ }
+
if (plen > len)
plen = len;
lnb->lnb_file_offset = offset;
(*nrpages)++;
}
- RETURN(0);
+ RETURN(rc);
}
static struct page *osd_get_page(const struct lu_env *env, struct dt_object *dt,
*/
static int osd_bufs_get(const struct lu_env *env, struct dt_object *dt,
loff_t pos, ssize_t len, struct niobuf_local *lnb,
- enum dt_bufs_type rw)
+ int maxlnb, enum dt_bufs_type rw)
{
struct osd_thread_info *oti = osd_oti_get(env);
struct osd_object *obj = osd_dt_obj(dt);
}
}
- osd_map_remote_to_local(pos, len, &npages, lnb);
+ rc = osd_map_remote_to_local(pos, len, &npages, lnb, maxlnb);
+ if (rc)
+ RETURN(rc);
/* this could also try less hard for DT_BUFS_TYPE_READAHEAD pages */
gfp_mask = rw & DT_BUFS_TYPE_LOCAL ? (GFP_NOFS | __GFP_HIGHMEM) :
* \retval negative error number of failure
*/
static int osd_bufs_get_read(const struct lu_env *env, struct osd_object *obj,
- loff_t off, ssize_t len, struct niobuf_local *lnb)
+ loff_t off, ssize_t len, struct niobuf_local *lnb,
+ int maxlnb)
{
struct osd_device *osd = osd_obj2dev(obj);
int rc, i, numbufs, npages = 0, drop_cache = 0;
off + len > obj->oo_dn->dn_datablksz)
len = obj->oo_dn->dn_datablksz - off;
+ dbp = NULL;
+ if (unlikely(npages >= maxlnb))
+ GOTO(err, rc = -EOVERFLOW);
+
rc = -dmu_buf_hold_array_by_bonus(&obj->oo_dn->dn_bonus->db,
off, len, TRUE, osd_0copy_tag,
&numbufs, &dbp);
dbf = (void *) ((unsigned long)dbp[i] | 1);
while (tocpy > 0) {
+ if (unlikely(npages >= maxlnb))
+ GOTO(err, rc = -EOVERFLOW);
+
thispage = PAGE_SIZE;
thispage -= bufoff & (PAGE_SIZE - 1);
thispage = min(tocpy, thispage);
err:
LASSERT(rc < 0);
+ if (dbp)
+ dmu_buf_rele_array(dbp, numbufs, osd_0copy_tag);
osd_bufs_put(env, &obj->oo_dt, lnb - npages, npages);
RETURN(rc);
}
}
static int osd_bufs_get_write(const struct lu_env *env, struct osd_object *obj,
- loff_t off, ssize_t len, struct niobuf_local *lnb)
+ loff_t off, ssize_t len, struct niobuf_local *lnb,
+ int maxlnb)
{
struct osd_device *osd = osd_obj2dev(obj);
int poff, plen, off_in_block, sz_in_block;
* so that we're sure nobody is trying to update the same block
*/
while (len > 0) {
- LASSERT(npages < PTLRPC_MAX_BRW_PAGES);
+ if (unlikely(npages >= maxlnb))
+ GOTO(out_err, rc = -EOVERFLOW);
off_in_block = off & (bs - 1);
sz_in_block = min_t(int, bs - off_in_block, len);
while (sz_in_block > 0) {
plen = min_t(int, sz_in_block, PAGE_SIZE);
+ if (unlikely(npages >= maxlnb))
+ GOTO(out_err, rc = -EOVERFLOW);
+
lnb[i].lnb_file_offset = off;
lnb[i].lnb_page_offset = 0;
lnb[i].lnb_len = plen;
PAGE_SIZE);
plen -= poff;
+ if (unlikely(npages >= maxlnb))
+ GOTO(out_err, rc = -EOVERFLOW);
+
lnb[i].lnb_file_offset = off;
lnb[i].lnb_page_offset = poff;
poff = 0;
static int osd_bufs_get(const struct lu_env *env, struct dt_object *dt,
loff_t offset, ssize_t len, struct niobuf_local *lnb,
- enum dt_bufs_type rw)
+ int maxlnb, enum dt_bufs_type rw)
{
struct osd_object *obj = osd_dt_obj(dt);
int rc;
LASSERT(obj->oo_dn);
if (rw & DT_BUFS_TYPE_WRITE)
- rc = osd_bufs_get_write(env, obj, offset, len, lnb);
+ rc = osd_bufs_get_write(env, obj, offset, len, lnb, maxlnb);
else
- rc = osd_bufs_get_read(env, obj, offset, len, lnb);
+ rc = osd_bufs_get_read(env, obj, offset, len, lnb, maxlnb);
return rc;
}
}
run_test 818 "unlink with failed llog"
+test_819a() {
+ dd if=/dev/zero of=$DIR/$tfile bs=1M count=1
+ cancel_lru_locks osc
+ #define OBD_FAIL_OST_2BIG_NIOBUF 0x248
+ do_facet $SINGLEMDS lctl set_param fail_loc=0x80000248
+ dd if=$DIR/$tfile of=/dev/null bs=1M count=1
+ rm -f $TDIR/$tfile
+}
+run_test 819a "too big niobuf in read"
+
+test_819b() {
+ #define OBD_FAIL_OST_2BIG_NIOBUF 0x248
+ do_facet $SINGLEMDS lctl set_param fail_loc=0x80000248
+ dd if=/dev/zero of=$DIR/$tfile bs=1M count=1
+ cancel_lru_locks osc
+ sleep 1
+ rm -f $TDIR/$tfile
+}
+run_test 819b "too big niobuf in write"
+
#
# tests that do cleanup/setup should be run at the end
#