+ return fid_seq_is_idif(fid_seq(fid));
+}
+
+struct ost_id {
+ obd_id oi_id;
+ obd_seq oi_seq;
+};
+
+static inline int fid_seq_is_norm(const __u64 seq)
+{
+ return (seq >= FID_SEQ_NORMAL);
+}
+
+static inline int fid_is_norm(const struct lu_fid *fid)
+{
+ return fid_seq_is_norm(fid_seq(fid));
+}
+
+/* convert an OST objid into an IDIF FID SEQ number */
+static inline obd_seq fid_idif_seq(obd_id id, __u32 ost_idx)
+{
+ return FID_SEQ_IDIF | (ost_idx << 16) | ((id >> 32) & 0xffff);
+}
+
+/* convert a packed IDIF FID into an OST objid */
+static inline obd_id fid_idif_id(obd_seq seq, __u32 oid, __u32 ver)
+{
+ return ((__u64)ver << 48) | ((seq & 0xffff) << 32) | oid;
+}
+
+/* unpack an ostid (id/seq) from a wire/disk structure into an IDIF FID */
+static inline void ostid_idif_unpack(struct ost_id *ostid,
+ struct lu_fid *fid, __u32 ost_idx)
+{
+ fid->f_seq = fid_idif_seq(ostid->oi_id, ost_idx);
+ fid->f_oid = ostid->oi_id; /* truncate to 32 bits by assignment */
+ fid->f_ver = ostid->oi_id >> 48; /* in theory, not currently used */
+}
+
+/* unpack an ostid (id/seq) from a wire/disk structure into a non-IDIF FID */
+static inline void ostid_fid_unpack(struct ost_id *ostid, struct lu_fid *fid)
+{
+ fid->f_seq = ostid->oi_seq;
+ fid->f_oid = ostid->oi_id; /* truncate to 32 bits by assignment */
+ fid->f_ver = ostid->oi_id >> 32; /* in theory, not currently used */
+}
+
+/* Unpack an OST object id/seq (group) into a FID. This is needed for
+ * converting all obdo, lmm, lsm, etc. 64-bit id/seq pairs into proper
+ * FIDs. Note that if an id/seq is already in FID/IDIF format it will
+ * be passed through unchanged. Only legacy OST objects in "group 0"
+ * will be mapped into the IDIF namespace so that they can fit into the
+ * struct lu_fid fields without loss. For reference see:
+ * http://arch.lustre.org/index.php?title=Interoperability_fids_zfs
+ */
+static inline int fid_ostid_unpack(struct lu_fid *fid, struct ost_id *ostid,
+ __u32 ost_idx)
+{
+ if (ost_idx > 0xffff) {
+ CERROR("bad ost_idx, seq:"LPU64" id:"LPU64" ost_idx:%u\n",
+ ostid->oi_seq, ostid->oi_id, ost_idx);
+ return -EBADF;
+ }
+
+ if (fid_seq_is_mdt0(ostid->oi_seq)) {
+ /* This is a "legacy" (old 1.x/2.early) OST object in "group 0"
+ * that we map into the IDIF namespace. It allows up to 2^48
+ * objects per OST, as this is the object namespace that has
+ * been in production for years. This can handle create rates
+ * of 1M objects/s/OST for 9 years, or combinations thereof. */
+ if (ostid->oi_id >= IDIF_MAX_OID) {
+ CERROR("bad MDT0 id, seq:"LPU64" id:"LPU64" ost_idx:%u\n",
+ ostid->oi_seq, ostid->oi_id, ost_idx);
+ return -EBADF;
+ }
+ ostid_idif_unpack(ostid, fid, ost_idx);
+
+ } else if (fid_seq_is_rsvd(ostid->oi_seq)) {
+ /* These are legacy OST objects for LLOG/ECHO and CMD testing.
+ * We only support 2^32 objects in these groups, and cannot
+ * uniquely identify them in the system (i.e. they are the
+ * duplicated on all OSTs), but this is not strictly required
+ * for the old object protocol, which has a separate ost_idx. */
+ if (ostid->oi_id >= 0xffffffffULL) {
+ CERROR("bad RSVD id, seq:"LPU64" id:"LPU64" ost_idx:%u\n",
+ ostid->oi_seq, ostid->oi_id, ost_idx);
+ return -EBADF;
+ }
+ ostid_fid_unpack(ostid, fid);
+
+ } else if (unlikely(fid_seq_is_igif(ostid->oi_seq))) {
+ /* This is an MDT inode number, which should never collide with
+ * proper OST object IDs, and is probably a broken filesystem */
+ CERROR("bad IGIF, seq:"LPU64" id:"LPU64" ost_idx:%u\n",
+ ostid->oi_seq, ostid->oi_id, ost_idx);
+ return -EBADF;
+
+ } else /* if (fid_seq_is_idif(seq) || fid_seq_is_norm(seq)) */ {
+ /* This is either an IDIF object, which identifies objects across
+ * all OSTs, or a regular FID. The IDIF namespace maps legacy
+ * OST objects into the FID namespace. In both cases, we just
+ * pass the FID through, no conversion needed. */
+ ostid_fid_unpack(ostid, fid);
+ }
+
+ return 0;
+}
+
+/* pack an IDIF FID into an ostid (id/seq) for the wire/disk */
+static inline void ostid_idif_pack(struct lu_fid *fid, struct ost_id *ostid)
+{
+ ostid->oi_seq = FID_SEQ_OST_MDT0;
+ ostid->oi_id = fid_idif_id(fid->f_seq, fid->f_oid, fid->f_ver);
+}
+
+/* pack a non-IDIF FID into an ostid (id/seq) for the wire/disk */
+static inline void ostid_fid_pack(struct lu_fid *fid, struct ost_id *ostid)
+{
+ ostid->oi_seq = fid_seq(fid);
+ ostid->oi_id = fid_ver_oid(fid);
+}
+
+/* pack any OST FID into an ostid (id/seq) for the wire/disk */
+static inline int fid_ostid_pack(struct lu_fid *fid, struct ost_id *ostid)
+{
+ if (unlikely(fid_seq_is_igif(fid->f_seq))) {
+ CERROR("bad IGIF, "DFID"\n", PFID(fid));
+ return -EBADF;
+ }
+
+ if (fid_is_idif(fid))
+ ostid_idif_pack(fid, ostid);
+ else
+ ostid_fid_pack(fid, ostid);
+
+ return 0;
+}
+
+/* extract OST sequence (group) from a wire ost_id (id/seq) pair */
+static inline obd_seq ostid_seq(struct ost_id *ostid)
+{
+ if (unlikely(fid_seq_is_igif(ostid->oi_seq)))
+ CWARN("bad IGIF, oi_seq: "LPU64" oi_id: "LPX64"\n",
+ ostid->oi_seq, ostid->oi_id);
+
+ if (unlikely(fid_seq_is_idif(ostid->oi_seq)))
+ return FID_SEQ_OST_MDT0;
+
+ return ostid->oi_seq;
+}
+
+/* extract OST objid from a wire ost_id (id/seq) pair */
+static inline obd_id ostid_id(struct ost_id *ostid)
+{
+ if (ostid->oi_seq == FID_SEQ_OST_MDT0)
+ return ostid->oi_id & IDIF_OID_MASK;
+
+ if (fid_seq_is_rsvd(ostid->oi_seq))
+ return ostid->oi_id & OBIF_OID_MASK;
+
+ if (fid_seq_is_idif(ostid->oi_seq))
+ return fid_idif_id(ostid->oi_seq, ostid->oi_id, 0);
+
+ return ostid->oi_id;