Commit b819ed4b authored by Trond Myklebust's avatar Trond Myklebust

pNFS/flexfiles: Improve merging of errors in LAYOUTRETURN

When we hit 22 errors, we start to overflow the memory buffers allocated
to the LAYOUTRETURN errors. The issue is that currently, RPC call reply
ordering determines how successful we are in merging errors that refer
to contiguous READ or WRITE requests.

Fix is to use an insertion sort to help detect contiguity.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent 13331a55
...@@ -218,63 +218,55 @@ static void extend_ds_error(struct nfs4_ff_layout_ds_err *err, ...@@ -218,63 +218,55 @@ static void extend_ds_error(struct nfs4_ff_layout_ds_err *err,
err->length = end - err->offset; err->length = end - err->offset;
} }
static bool ds_error_can_merge(struct nfs4_ff_layout_ds_err *err, u64 offset, static int
u64 length, int status, enum nfs_opnum4 opnum, ff_ds_error_match(const struct nfs4_ff_layout_ds_err *e1,
nfs4_stateid *stateid, const struct nfs4_ff_layout_ds_err *e2)
struct nfs4_deviceid *deviceid)
{ {
return err->status == status && err->opnum == opnum && int ret;
nfs4_stateid_match(&err->stateid, stateid) &&
!memcmp(&err->deviceid, deviceid, sizeof(*deviceid)) && if (e1->opnum != e2->opnum)
end_offset(err->offset, err->length) >= offset && return e1->opnum < e2->opnum ? -1 : 1;
err->offset <= end_offset(offset, length); if (e1->status != e2->status)
} return e1->status < e2->status ? -1 : 1;
ret = memcmp(&e1->stateid, &e2->stateid, sizeof(e1->stateid));
static bool merge_ds_error(struct nfs4_ff_layout_ds_err *old, if (ret != 0)
struct nfs4_ff_layout_ds_err *new) return ret;
{ ret = memcmp(&e1->deviceid, &e2->deviceid, sizeof(e1->deviceid));
if (!ds_error_can_merge(old, new->offset, new->length, new->status, if (ret != 0)
new->opnum, &new->stateid, &new->deviceid)) return ret;
return false; if (end_offset(e1->offset, e1->length) < e2->offset)
return -1;
extend_ds_error(old, new->offset, new->length); if (e1->offset > end_offset(e2->offset, e2->length))
return true; return 1;
/* If ranges overlap or are contiguous, they are the same */
return 0;
} }
static bool static void
ff_layout_add_ds_error_locked(struct nfs4_flexfile_layout *flo, ff_layout_add_ds_error_locked(struct nfs4_flexfile_layout *flo,
struct nfs4_ff_layout_ds_err *dserr) struct nfs4_ff_layout_ds_err *dserr)
{ {
struct nfs4_ff_layout_ds_err *err; struct nfs4_ff_layout_ds_err *err, *tmp;
struct list_head *head = &flo->error_list;
list_for_each_entry(err, &flo->error_list, list) { int match;
if (merge_ds_error(err, dserr)) {
return true; /* Do insertion sort w/ merges */
} list_for_each_entry_safe(err, tmp, &flo->error_list, list) {
} match = ff_ds_error_match(err, dserr);
if (match < 0)
list_add(&dserr->list, &flo->error_list); continue;
return false; if (match > 0) {
} /* Add entry "dserr" _before_ entry "err" */
head = &err->list;
static bool
ff_layout_update_ds_error(struct nfs4_flexfile_layout *flo, u64 offset,
u64 length, int status, enum nfs_opnum4 opnum,
nfs4_stateid *stateid, struct nfs4_deviceid *deviceid)
{
bool found = false;
struct nfs4_ff_layout_ds_err *err;
list_for_each_entry(err, &flo->error_list, list) {
if (ds_error_can_merge(err, offset, length, status, opnum,
stateid, deviceid)) {
found = true;
extend_ds_error(err, offset, length);
break; break;
} }
/* Entries match, so merge "err" into "dserr" */
extend_ds_error(dserr, err->offset, err->length);
list_del(&err->list);
kfree(err);
} }
return found; list_add_tail(&dserr->list, head);
} }
int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo, int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
...@@ -283,7 +275,6 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo, ...@@ -283,7 +275,6 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
gfp_t gfp_flags) gfp_t gfp_flags)
{ {
struct nfs4_ff_layout_ds_err *dserr; struct nfs4_ff_layout_ds_err *dserr;
bool needfree;
if (status == 0) if (status == 0)
return 0; return 0;
...@@ -291,14 +282,6 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo, ...@@ -291,14 +282,6 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
if (mirror->mirror_ds == NULL) if (mirror->mirror_ds == NULL)
return -EINVAL; return -EINVAL;
spin_lock(&flo->generic_hdr.plh_inode->i_lock);
if (ff_layout_update_ds_error(flo, offset, length, status, opnum,
&mirror->stateid,
&mirror->mirror_ds->id_node.deviceid)) {
spin_unlock(&flo->generic_hdr.plh_inode->i_lock);
return 0;
}
spin_unlock(&flo->generic_hdr.plh_inode->i_lock);
dserr = kmalloc(sizeof(*dserr), gfp_flags); dserr = kmalloc(sizeof(*dserr), gfp_flags);
if (!dserr) if (!dserr)
return -ENOMEM; return -ENOMEM;
...@@ -313,10 +296,8 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo, ...@@ -313,10 +296,8 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
NFS4_DEVICEID4_SIZE); NFS4_DEVICEID4_SIZE);
spin_lock(&flo->generic_hdr.plh_inode->i_lock); spin_lock(&flo->generic_hdr.plh_inode->i_lock);
needfree = ff_layout_add_ds_error_locked(flo, dserr); ff_layout_add_ds_error_locked(flo, dserr);
spin_unlock(&flo->generic_hdr.plh_inode->i_lock); spin_unlock(&flo->generic_hdr.plh_inode->i_lock);
if (needfree)
kfree(dserr);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment