Skip to content

Commit

Permalink
Cleanup XDR parsing for LAYOUTGET, GETDEVICEINFO
Browse files Browse the repository at this point in the history
changes LAYOUTGET and GETDEVICEINFO XDR parsing to:
 - not use vmap, which doesn't work on incoherent archs
 - use xdr_stream parsing for all xdr

Signed-off-by: Weston Andros Adamson <[email protected]>
Signed-off-by: Trond Myklebust <[email protected]>
  • Loading branch information
westonandrosadamson authored and Trond Myklebust committed Mar 24, 2011
1 parent ef31153 commit 35124a0
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 86 deletions.
53 changes: 44 additions & 9 deletions fs/nfs/nfs4filelayout.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,12 +502,33 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
struct nfs4_layoutget_res *lgr,
struct nfs4_deviceid *id)
{
uint32_t *p = (uint32_t *)lgr->layout.buf;
struct xdr_stream stream;
struct xdr_buf buf = {
.pages = lgr->layoutp->pages,
.page_len = lgr->layoutp->len,
.buflen = lgr->layoutp->len,
.len = lgr->layoutp->len,
};
struct page *scratch;
__be32 *p;
uint32_t nfl_util;
int i;

dprintk("%s: set_layout_map Begin\n", __func__);

scratch = alloc_page(GFP_KERNEL);
if (!scratch)
return -ENOMEM;

xdr_init_decode(&stream, &buf, NULL);
xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);

/* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8),
* num_fh (4) */
p = xdr_inline_decode(&stream, NFS4_DEVICEID4_SIZE + 20);
if (unlikely(!p))
goto out_err;

memcpy(id, p, sizeof(*id));
p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
print_deviceid(id);
Expand All @@ -529,32 +550,46 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
__func__, nfl_util, fl->num_fh, fl->first_stripe_index,
fl->pattern_offset);

if (!fl->num_fh)
goto out_err;

fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *),
GFP_KERNEL);
if (!fl->fh_array)
return -ENOMEM;
goto out_err;

for (i = 0; i < fl->num_fh; i++) {
/* Do we want to use a mempool here? */
fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
if (!fl->fh_array[i]) {
filelayout_free_fh_array(fl);
return -ENOMEM;
}
if (!fl->fh_array[i])
goto out_err_free;

p = xdr_inline_decode(&stream, 4);
if (unlikely(!p))
goto out_err_free;
fl->fh_array[i]->size = be32_to_cpup(p++);
if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
printk(KERN_ERR "Too big fh %d received %d\n",
i, fl->fh_array[i]->size);
filelayout_free_fh_array(fl);
return -EIO;
goto out_err_free;
}

p = xdr_inline_decode(&stream, fl->fh_array[i]->size);
if (unlikely(!p))
goto out_err_free;
memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size);
p += XDR_QUADLEN(fl->fh_array[i]->size);
dprintk("DEBUG: %s: fh len %d\n", __func__,
fl->fh_array[i]->size);
}

__free_page(scratch);
return 0;

out_err_free:
filelayout_free_fh_array(fl);
out_err:
__free_page(scratch);
return -EIO;
}

static void
Expand Down
178 changes: 122 additions & 56 deletions fs/nfs/nfs4filelayoutdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,33 +261,42 @@ nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port)
* Currently only support ipv4, and one multi-path address.
*/
static struct nfs4_pnfs_ds *
decode_and_add_ds(__be32 **pp, struct inode *inode)
decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode)
{
struct nfs4_pnfs_ds *ds = NULL;
char *buf;
const char *ipend, *pstr;
u32 ip_addr, port;
int nlen, rlen, i;
int tmp[2];
__be32 *r_netid, *r_addr, *p = *pp;
__be32 *p;

/* r_netid */
p = xdr_inline_decode(streamp, 4);
if (unlikely(!p))
goto out_err;
nlen = be32_to_cpup(p++);
r_netid = p;
p += XDR_QUADLEN(nlen);

/* r_addr */
rlen = be32_to_cpup(p++);
r_addr = p;
p += XDR_QUADLEN(rlen);
*pp = p;
p = xdr_inline_decode(streamp, nlen);
if (unlikely(!p))
goto out_err;

/* Check that netid is "tcp" */
if (nlen != 3 || memcmp((char *)r_netid, "tcp", 3)) {
if (nlen != 3 || memcmp((char *)p, "tcp", 3)) {
dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__);
goto out_err;
}

/* r_addr */
p = xdr_inline_decode(streamp, 4);
if (unlikely(!p))
goto out_err;
rlen = be32_to_cpup(p);

p = xdr_inline_decode(streamp, rlen);
if (unlikely(!p))
goto out_err;

/* ipv6 length plus port is legal */
if (rlen > INET6_ADDRSTRLEN + 8) {
dprintk("%s: Invalid address, length %d\n", __func__,
Expand All @@ -300,7 +309,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
goto out_err;
}
buf[rlen] = '\0';
memcpy(buf, r_addr, rlen);
memcpy(buf, p, rlen);

/* replace the port dots with dashes for the in4_pton() delimiter*/
for (i = 0; i < 2; i++) {
Expand Down Expand Up @@ -336,90 +345,154 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
static struct nfs4_file_layout_dsaddr*
decode_device(struct inode *ino, struct pnfs_device *pdev)
{
int i, dummy;
int i;
u32 cnt, num;
u8 *indexp;
__be32 *p = (__be32 *)pdev->area, *indicesp;
struct nfs4_file_layout_dsaddr *dsaddr;
__be32 *p;
u8 *stripe_indices;
u8 max_stripe_index;
struct nfs4_file_layout_dsaddr *dsaddr = NULL;
struct xdr_stream stream;
struct xdr_buf buf = {
.pages = pdev->pages,
.page_len = pdev->pglen,
.buflen = pdev->pglen,
.len = pdev->pglen,
};
struct page *scratch;

/* set up xdr stream */
scratch = alloc_page(GFP_KERNEL);
if (!scratch)
goto out_err;

xdr_init_decode(&stream, &buf, NULL);
xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);

/* Get the stripe count (number of stripe index) */
cnt = be32_to_cpup(p++);
p = xdr_inline_decode(&stream, 4);
if (unlikely(!p))
goto out_err_free_scratch;

cnt = be32_to_cpup(p);
dprintk("%s stripe count %d\n", __func__, cnt);
if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
printk(KERN_WARNING "%s: stripe count %d greater than "
"supported maximum %d\n", __func__,
cnt, NFS4_PNFS_MAX_STRIPE_CNT);
goto out_err;
goto out_err_free_scratch;
}

/* read stripe indices */
stripe_indices = kcalloc(cnt, sizeof(u8), GFP_KERNEL);
if (!stripe_indices)
goto out_err_free_scratch;

p = xdr_inline_decode(&stream, cnt << 2);
if (unlikely(!p))
goto out_err_free_stripe_indices;

indexp = &stripe_indices[0];
max_stripe_index = 0;
for (i = 0; i < cnt; i++) {
*indexp = be32_to_cpup(p++);
max_stripe_index = max(max_stripe_index, *indexp);
indexp++;
}

/* Check the multipath list count */
indicesp = p;
p += XDR_QUADLEN(cnt << 2);
num = be32_to_cpup(p++);
p = xdr_inline_decode(&stream, 4);
if (unlikely(!p))
goto out_err_free_stripe_indices;

num = be32_to_cpup(p);
dprintk("%s ds_num %u\n", __func__, num);
if (num > NFS4_PNFS_MAX_MULTI_CNT) {
printk(KERN_WARNING "%s: multipath count %d greater than "
"supported maximum %d\n", __func__,
num, NFS4_PNFS_MAX_MULTI_CNT);
goto out_err;
goto out_err_free_stripe_indices;
}

/* validate stripe indices are all < num */
if (max_stripe_index >= num) {
printk(KERN_WARNING "%s: stripe index %u >= num ds %u\n",
__func__, max_stripe_index, num);
goto out_err_free_stripe_indices;
}

dsaddr = kzalloc(sizeof(*dsaddr) +
(sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
GFP_KERNEL);
if (!dsaddr)
goto out_err;

dsaddr->stripe_indices = kzalloc(sizeof(u8) * cnt, GFP_KERNEL);
if (!dsaddr->stripe_indices)
goto out_err_free;
goto out_err_free_stripe_indices;

dsaddr->stripe_count = cnt;
dsaddr->stripe_indices = stripe_indices;
stripe_indices = NULL;
dsaddr->ds_num = num;

memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id));

/* Go back an read stripe indices */
p = indicesp;
indexp = &dsaddr->stripe_indices[0];
for (i = 0; i < dsaddr->stripe_count; i++) {
*indexp = be32_to_cpup(p++);
if (*indexp >= num)
goto out_err_free;
indexp++;
}
/* Skip already read multipath list count */
p++;

for (i = 0; i < dsaddr->ds_num; i++) {
int j;
u32 mp_count;

p = xdr_inline_decode(&stream, 4);
if (unlikely(!p))
goto out_err_free_deviceid;

dummy = be32_to_cpup(p++); /* multipath count */
if (dummy > 1) {
mp_count = be32_to_cpup(p); /* multipath count */
if (mp_count > 1) {
printk(KERN_WARNING
"%s: Multipath count %d not supported, "
"skipping all greater than 1\n", __func__,
dummy);
mp_count);
}
for (j = 0; j < dummy; j++) {
for (j = 0; j < mp_count; j++) {
if (j == 0) {
dsaddr->ds_list[i] = decode_and_add_ds(&p, ino);
dsaddr->ds_list[i] = decode_and_add_ds(&stream,
ino);
if (dsaddr->ds_list[i] == NULL)
goto out_err_free;
goto out_err_free_deviceid;
} else {
u32 len;
/* skip extra multipath */
len = be32_to_cpup(p++);
p += XDR_QUADLEN(len);
len = be32_to_cpup(p++);
p += XDR_QUADLEN(len);
continue;

/* read len, skip */
p = xdr_inline_decode(&stream, 4);
if (unlikely(!p))
goto out_err_free_deviceid;
len = be32_to_cpup(p);

p = xdr_inline_decode(&stream, len);
if (unlikely(!p))
goto out_err_free_deviceid;

/* read len, skip */
p = xdr_inline_decode(&stream, 4);
if (unlikely(!p))
goto out_err_free_deviceid;
len = be32_to_cpup(p);

p = xdr_inline_decode(&stream, len);
if (unlikely(!p))
goto out_err_free_deviceid;
}
}
}

__free_page(scratch);
return dsaddr;

out_err_free:
out_err_free_deviceid:
nfs4_fl_free_deviceid(dsaddr);
/* stripe_indicies was part of dsaddr */
goto out_err_free_scratch;
out_err_free_stripe_indices:
kfree(stripe_indices);
out_err_free_scratch:
__free_page(scratch);
out_err:
dprintk("%s ERROR: returning NULL\n", __func__);
return NULL;
Expand Down Expand Up @@ -498,11 +571,6 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
goto out_free;
}

/* set pdev->area */
pdev->area = vmap(pages, max_pages, VM_MAP, PAGE_KERNEL);
if (!pdev->area)
goto out_free;

memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id));
pdev->layout_type = LAYOUT_NFSV4_1_FILES;
pdev->pages = pages;
Expand All @@ -521,8 +589,6 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
*/
dsaddr = decode_and_add_device(inode, pdev);
out_free:
if (pdev->area != NULL)
vunmap(pdev->area);
for (i = 0; i < max_pages; i++)
__free_page(pages[i]);
kfree(pages);
Expand Down
9 changes: 1 addition & 8 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -5526,8 +5526,6 @@ static void nfs4_layoutget_release(void *calldata)
struct nfs4_layoutget *lgp = calldata;

dprintk("--> %s\n", __func__);
if (lgp->res.layout.buf != NULL)
free_page((unsigned long) lgp->res.layout.buf);
put_nfs_open_context(lgp->args.ctx);
kfree(calldata);
dprintk("<-- %s\n", __func__);
Expand Down Expand Up @@ -5559,12 +5557,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)

dprintk("--> %s\n", __func__);

lgp->res.layout.buf = (void *)__get_free_page(GFP_NOFS);
if (lgp->res.layout.buf == NULL) {
nfs4_layoutget_release(lgp);
return -ENOMEM;
}

lgp->res.layoutp = &lgp->args.layout;
lgp->res.seq_res.sr_slot = NULL;
task = rpc_run_task(&task_setup_data);
if (IS_ERR(task))
Expand Down
Loading

0 comments on commit 35124a0

Please sign in to comment.