CEPH_MDS_OP_RMSNAP = 0x01401,
CEPH_MDS_OP_LSSNAP = 0x00402,
CEPH_MDS_OP_RENAMESNAP = 0x01403,
+ CEPH_MDS_OP_READDIR_SNAPDIFF = 0x01404,
// internal op
CEPH_MDS_OP_FRAGMENTDIR= 0x01500,
CEPH_MDS_OP_RDLOCK_FRAGSSTATS = 0x01507
};
+#define IS_CEPH_MDS_OP_NEWINODE(op) (op == CEPH_MDS_OP_CREATE || \
+ op == CEPH_MDS_OP_MKNOD || \
+ op == CEPH_MDS_OP_MKDIR || \
+ op == CEPH_MDS_OP_SYMLINK)
+
extern const char *ceph_mds_op_name(int op);
// setattr mask is an int
#define CEPH_XATTR_REMOVE (1 << 31)
/*
- * readdir request flags;
+ * readdir/readdir_snapdiff request flags;
*/
#define CEPH_READDIR_REPLY_BITFLAGS (1<<0)
/*
- * readdir reply flags.
+ * readdir/readdir_snapdiff reply flags.
*/
#define CEPH_READDIR_FRAG_END (1<<0)
#define CEPH_READDIR_FRAG_COMPLETE (1<<8)
__le64 parent;
__le32 hash;
} __attribute__ ((packed)) lookupino;
+ struct {
+ __le32 frag; /* which dir fragment */
+ __le32 max_entries; /* how many dentries to grab */
+ __le32 max_bytes;
+ __le16 flags;
+ __le32 offset_hash;
+ __le64 snap_other;
+ } __attribute__ ((packed)) snapdiff;
} __attribute__ ((packed));
-#define CEPH_MDS_REQUEST_HEAD_VERSION 2
+#define CEPH_MDS_REQUEST_HEAD_VERSION 3
/*
* Note that any change to this structure must ensure that it is compatible
__le32 ext_num_retry; /* new count retry attempts */
__le32 ext_num_fwd; /* new count fwd attempts */
+
+ __le32 struct_len; /* to store size of struct ceph_mds_request_head */
+ __le32 owner_uid, owner_gid; /* used for OPs which create inodes */
} __attribute__ ((packed));
-void inline encode(const struct ceph_mds_request_head& h, ceph::buffer::list& bl, bool old_version) {
+void inline encode(const struct ceph_mds_request_head& h, ceph::buffer::list& bl) {
using ceph::encode;
encode(h.version, bl);
encode(h.oldest_client_tid, bl);
encode(h.ino, bl);
bl.append((char*)&h.args, sizeof(h.args));
- if (!old_version) {
+ if (h.version >= 2) {
encode(h.ext_num_retry, bl);
encode(h.ext_num_fwd, bl);
}
+
+ if (h.version >= 3) {
+ __u32 struct_len = sizeof(struct ceph_mds_request_head);
+ encode(struct_len, bl);
+ encode(h.owner_uid, bl);
+ encode(h.owner_gid, bl);
+
+ /*
+ * Please, add new fields handling here.
+ * You don't need to check h.version as we do it
+ * in decode(), because decode can properly skip
+ * all unsupported fields if h.version >= 3.
+ */
+ }
}
void inline decode(struct ceph_mds_request_head& h, ceph::buffer::list::const_iterator& bl) {
using ceph::decode;
+ unsigned struct_end = bl.get_off();
+
decode(h.version, bl);
decode(h.oldest_client_tid, bl);
decode(h.mdsmap_epoch, bl);
h.ext_num_retry = h.num_retry;
h.ext_num_fwd = h.num_fwd;
}
+
+ if (h.version >= 3) {
+ decode(h.struct_len, bl);
+ struct_end += h.struct_len;
+
+ decode(h.owner_uid, bl);
+ decode(h.owner_gid, bl);
+ } else {
+ /*
+ * client is old: let's take caller_{u,g}id as owner_{u,g}id
+ * this is how it worked before adding of owner_{u,g}id fields.
+ */
+ h.owner_uid = h.caller_uid;
+ h.owner_gid = h.caller_gid;
+ }
+
+ /* add new fields handling here */
+
+ /*
+ * From version 3 we have struct_len field.
+ * It allows us to properly handle a case
+ * when client send struct ceph_mds_request_head
+ * bigger in size than MDS supports. In this
+ * case we just want to skip all remaining bytes
+ * at the end.
+ *
+ * See also DECODE_FINISH macro. Unfortunately,
+ * we can't start using it right now as it will be
+ * an incompatible protocol change.
+ */
+ if (h.version >= 3) {
+ if (bl.get_off() > struct_end)
+ throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__));
+ if (bl.get_off() < struct_end)
+ bl += struct_end - bl.get_off();
+ }
}
/* cap/lease release record */