Fix potential FSImage corruption. Contributed by Ekanth Sethuramalingam & Arpit Agarwal.

(cherry picked from commit 0a1e922f3d)
This commit is contained in:
Konstantin V Shvachko 2018-07-16 18:20:24 -07:00
parent 67ee584fd8
commit 475c282939
3 changed files with 49 additions and 28 deletions

View File

@ -38,7 +38,8 @@ import com.google.common.collect.ImmutableList;
* [1:3) -- the type of the entry (AclEntryType) <br> * [1:3) -- the type of the entry (AclEntryType) <br>
* [3:6) -- the permission of the entry (FsAction) <br> * [3:6) -- the permission of the entry (FsAction) <br>
* [6:7) -- A flag to indicate whether Named entry or not <br> * [6:7) -- A flag to indicate whether Named entry or not <br>
* [7:32) -- the name of the entry, which is an ID that points to a <br> * [7:8) -- Reserved <br>
* [8:32) -- the name of the entry, which is an ID that points to a <br>
* string in the StringTableSection. <br> * string in the StringTableSection. <br>
*/ */
public enum AclEntryStatusFormat { public enum AclEntryStatusFormat {
@ -47,7 +48,8 @@ public enum AclEntryStatusFormat {
TYPE(SCOPE.BITS, 2), TYPE(SCOPE.BITS, 2),
PERMISSION(TYPE.BITS, 3), PERMISSION(TYPE.BITS, 3),
NAMED_ENTRY_CHECK(PERMISSION.BITS, 1), NAMED_ENTRY_CHECK(PERMISSION.BITS, 1),
NAME(NAMED_ENTRY_CHECK.BITS, 25); RESERVED(NAMED_ENTRY_CHECK.BITS, 1),
NAME(RESERVED.BITS, 24);
private final LongBitFormat BITS; private final LongBitFormat BITS;

View File

@ -35,8 +35,8 @@ public abstract class INodeWithAdditionalFields extends INode
implements LinkedElement { implements LinkedElement {
enum PermissionStatusFormat { enum PermissionStatusFormat {
MODE(null, 16), MODE(null, 16),
GROUP(MODE.BITS, 25), GROUP(MODE.BITS, 24),
USER(GROUP.BITS, 23); USER(GROUP.BITS, 24);
final LongBitFormat BITS; final LongBitFormat BITS;

View File

@ -27,25 +27,56 @@ import org.apache.hadoop.hdfs.XAttrHelper;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import org.apache.hadoop.hdfs.util.LongBitFormat;
/** /**
* Class to pack XAttrs into byte[].<br> * Class to pack XAttrs into byte[].<br>
* For each XAttr:<br> * For each XAttr:<br>
* The first 4 bytes represents XAttr namespace and name<br> * The first 4 bytes represents XAttr namespace and name<br>
* [0:3) - XAttr namespace<br> * [0:3) - XAttr namespace<br>
* [3:32) - The name of the entry, which is an ID that points to a * [3:8) - Reserved<br>
* [8:32) - The name of the entry, which is an ID that points to a
* string in map<br> * string in map<br>
* The following two bytes represents the length of XAttr value<br> * The following two bytes represents the length of XAttr value<br>
* The remaining bytes is the XAttr value<br> * The remaining bytes is the XAttr value<br>
*/ */
class XAttrFormat { class XAttrFormat {
private static final int XATTR_NAMESPACE_MASK = (1 << 3) - 1; private enum XAttrStatusFormat {
private static final int XATTR_NAMESPACE_OFFSET = 29;
private static final int XATTR_NAME_MASK = (1 << 29) - 1; NAMESPACE(null, 3),
private static final int XATTR_NAME_ID_MAX = 1 << 29; RESERVED(NAMESPACE.BITS, 5),
NAME(RESERVED.BITS, 24);
private final LongBitFormat BITS;
XAttrStatusFormat(LongBitFormat previous, int length) {
BITS = new LongBitFormat(name(), previous, length, 0);
}
static XAttr.NameSpace getNamespace(int xattrStatus) {
int ordinal = (int) NAMESPACE.BITS.retrieve(xattrStatus);
return XAttr.NameSpace.values()[ordinal];
}
static String getName(int xattrStatus) {
int id = (int) NAME.BITS.retrieve(xattrStatus);
return XAttrStorage.getName(id);
}
static int toInt(XAttr.NameSpace namespace, String name) {
long xattrStatusInt = 0;
xattrStatusInt = NAMESPACE.BITS
.combine(namespace.ordinal(), xattrStatusInt);
int nid = XAttrStorage.getNameSerialNumber(name);
xattrStatusInt = NAME.BITS
.combine(nid, xattrStatusInt);
return (int) xattrStatusInt;
}
}
private static final int XATTR_VALUE_LEN_MAX = 1 << 16; private static final int XATTR_VALUE_LEN_MAX = 1 << 16;
private static final XAttr.NameSpace[] XATTR_NAMESPACE_VALUES =
XAttr.NameSpace.values();
/** /**
* Unpack byte[] to XAttrs. * Unpack byte[] to XAttrs.
@ -64,10 +95,8 @@ class XAttrFormat {
int v = Ints.fromBytes(attrs[i], attrs[i + 1], int v = Ints.fromBytes(attrs[i], attrs[i + 1],
attrs[i + 2], attrs[i + 3]); attrs[i + 2], attrs[i + 3]);
i += 4; i += 4;
int ns = (v >> XATTR_NAMESPACE_OFFSET) & XATTR_NAMESPACE_MASK; builder.setNameSpace(XAttrStatusFormat.getNamespace(v));
int nid = v & XATTR_NAME_MASK; builder.setName(XAttrStatusFormat.getName(v));
builder.setNameSpace(XATTR_NAMESPACE_VALUES[ns]);
builder.setName(XAttrStorage.getName(nid));
int vlen = ((0xff & attrs[i]) << 8) | (0xff & attrs[i + 1]); int vlen = ((0xff & attrs[i]) << 8) | (0xff & attrs[i + 1]);
i += 2; i += 2;
if (vlen > 0) { if (vlen > 0) {
@ -100,10 +129,8 @@ class XAttrFormat {
int v = Ints.fromBytes(attrs[i], attrs[i + 1], int v = Ints.fromBytes(attrs[i], attrs[i + 1],
attrs[i + 2], attrs[i + 3]); attrs[i + 2], attrs[i + 3]);
i += 4; i += 4;
int ns = (v >> XATTR_NAMESPACE_OFFSET) & XATTR_NAMESPACE_MASK; XAttr.NameSpace namespace = XAttrStatusFormat.getNamespace(v);
int nid = v & XATTR_NAME_MASK; String name = XAttrStatusFormat.getName(v);
XAttr.NameSpace namespace = XATTR_NAMESPACE_VALUES[ns];
String name = XAttrStorage.getName(nid);
int vlen = ((0xff & attrs[i]) << 8) | (0xff & attrs[i + 1]); int vlen = ((0xff & attrs[i]) << 8) | (0xff & attrs[i + 1]);
i += 2; i += 2;
if (xAttr.getNameSpace() == namespace && if (xAttr.getNameSpace() == namespace &&
@ -134,15 +161,7 @@ class XAttrFormat {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
try { try {
for (XAttr a : xAttrs) { for (XAttr a : xAttrs) {
int nsOrd = a.getNameSpace().ordinal(); int v = XAttrStatusFormat.toInt(a.getNameSpace(), a.getName());
Preconditions.checkArgument(nsOrd < 8, "Too many namespaces.");
int nid = XAttrStorage.getNameSerialNumber(a.getName());
Preconditions.checkArgument(nid < XATTR_NAME_ID_MAX,
"Too large serial number of the xattr name");
// big-endian
int v = ((nsOrd & XATTR_NAMESPACE_MASK) << XATTR_NAMESPACE_OFFSET)
| (nid & XATTR_NAME_MASK);
out.write(Ints.toByteArray(v)); out.write(Ints.toByteArray(v));
int vlen = a.getValue() == null ? 0 : a.getValue().length; int vlen = a.getValue() == null ? 0 : a.getValue().length;
Preconditions.checkArgument(vlen < XATTR_VALUE_LEN_MAX, Preconditions.checkArgument(vlen < XATTR_VALUE_LEN_MAX,