mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 08:49:45 +00:00
Merge branch 'bugfixes'
* bugfixes: pNFS/flexfiles: Fix an XDR encoding bug in layoutreturn pNFS/flexfiles: Improve merging of errors in LAYOUTRETURN
This commit is contained in:
commit
6d45c042f3
2 changed files with 41 additions and 62 deletions
|
@ -1948,11 +1948,9 @@ ff_layout_encode_layoutreturn(struct pnfs_layout_hdr *lo,
|
|||
start = xdr_reserve_space(xdr, 4);
|
||||
BUG_ON(!start);
|
||||
|
||||
if (ff_layout_encode_ioerr(flo, xdr, args))
|
||||
goto out;
|
||||
|
||||
ff_layout_encode_ioerr(flo, xdr, args);
|
||||
ff_layout_encode_iostats(flo, xdr, args);
|
||||
out:
|
||||
|
||||
*start = cpu_to_be32((xdr->p - start - 1) * 4);
|
||||
dprintk("%s: Return\n", __func__);
|
||||
}
|
||||
|
|
|
@ -218,63 +218,55 @@ static void extend_ds_error(struct nfs4_ff_layout_ds_err *err,
|
|||
err->length = end - err->offset;
|
||||
}
|
||||
|
||||
static bool ds_error_can_merge(struct nfs4_ff_layout_ds_err *err, u64 offset,
|
||||
u64 length, int status, enum nfs_opnum4 opnum,
|
||||
nfs4_stateid *stateid,
|
||||
struct nfs4_deviceid *deviceid)
|
||||
static int
|
||||
ff_ds_error_match(const struct nfs4_ff_layout_ds_err *e1,
|
||||
const struct nfs4_ff_layout_ds_err *e2)
|
||||
{
|
||||
return err->status == status && err->opnum == opnum &&
|
||||
nfs4_stateid_match(&err->stateid, stateid) &&
|
||||
!memcmp(&err->deviceid, deviceid, sizeof(*deviceid)) &&
|
||||
end_offset(err->offset, err->length) >= offset &&
|
||||
err->offset <= end_offset(offset, length);
|
||||
int ret;
|
||||
|
||||
if (e1->opnum != e2->opnum)
|
||||
return e1->opnum < e2->opnum ? -1 : 1;
|
||||
if (e1->status != e2->status)
|
||||
return e1->status < e2->status ? -1 : 1;
|
||||
ret = memcmp(&e1->stateid, &e2->stateid, sizeof(e1->stateid));
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = memcmp(&e1->deviceid, &e2->deviceid, sizeof(e1->deviceid));
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (end_offset(e1->offset, e1->length) < e2->offset)
|
||||
return -1;
|
||||
if (e1->offset > end_offset(e2->offset, e2->length))
|
||||
return 1;
|
||||
/* If ranges overlap or are contiguous, they are the same */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool merge_ds_error(struct nfs4_ff_layout_ds_err *old,
|
||||
struct nfs4_ff_layout_ds_err *new)
|
||||
{
|
||||
if (!ds_error_can_merge(old, new->offset, new->length, new->status,
|
||||
new->opnum, &new->stateid, &new->deviceid))
|
||||
return false;
|
||||
|
||||
extend_ds_error(old, new->offset, new->length);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
static void
|
||||
ff_layout_add_ds_error_locked(struct nfs4_flexfile_layout *flo,
|
||||
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;
|
||||
int match;
|
||||
|
||||
list_for_each_entry(err, &flo->error_list, list) {
|
||||
if (merge_ds_error(err, dserr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
list_add(&dserr->list, &flo->error_list);
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
/* 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)
|
||||
continue;
|
||||
if (match > 0) {
|
||||
/* Add entry "dserr" _before_ entry "err" */
|
||||
head = &err->list;
|
||||
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,
|
||||
|
@ -283,7 +275,6 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
|
|||
gfp_t gfp_flags)
|
||||
{
|
||||
struct nfs4_ff_layout_ds_err *dserr;
|
||||
bool needfree;
|
||||
|
||||
if (status == 0)
|
||||
return 0;
|
||||
|
@ -291,14 +282,6 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
|
|||
if (mirror->mirror_ds == NULL)
|
||||
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);
|
||||
if (!dserr)
|
||||
return -ENOMEM;
|
||||
|
@ -313,10 +296,8 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
|
|||
NFS4_DEVICEID4_SIZE);
|
||||
|
||||
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);
|
||||
if (needfree)
|
||||
kfree(dserr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue