| @@ -2881,6 +2881,17 @@ static void encode_mclientrequest_tail(void **p, · 2880 unmodified lines |
| 2881 | 2881 | } |
| 2882 | 2882 | } |
| 2883 | 2883 | |
| 2884 | +static inline u16 mds_supported_head_version(struct ceph_mds_session *session) |
| 2885 | +{ |
| 2886 | + if (!test_bit(CEPHFS_FEATURE_32BITS_RETRY_FWD, &session->s_features)) |
| 2887 | + return 1; |
| 2888 | + |
| 2889 | + if (!test_bit(CEPHFS_FEATURE_HAS_OWNER_UIDGID, &session->s_features)) |
| 2890 | + return 2; |
| 2891 | + |
| 2892 | + return CEPH_MDS_REQUEST_HEAD_VERSION; |
| 2893 | +} |
| 2894 | + |
| 2884 | 2895 | static struct ceph_mds_request_head_legacy * |
| 2885 | 2896 | find_legacy_request_head(void *p, u64 features) |
| 2886 | 2897 | { |
| @@ -2902,6 +2913,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 15 unmodified lines |
| 2902 | 2913 | { |
| 2903 | 2914 | int mds = session->s_mds; |
| 2904 | 2915 | struct ceph_mds_client *mdsc = session->s_mdsc; |
| 2916 | + struct ceph_client *cl = mdsc->fsc->client; |
| 2905 | 2917 | struct ceph_msg *msg; |
| 2906 | 2918 | struct ceph_mds_request_head_legacy *lhead; |
| 2907 | 2919 | const char *path1 = NULL; |
| @@ -2915,8 +2927,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 7 unmodified lines |
| 2915 | 2927 | void *p, *end; |
| 2916 | 2928 | int ret; |
| 2917 | 2929 | bool legacy = !(session->s_con.peer_features & CEPH_FEATURE_FS_BTIME); |
| 2918 | | − bool old_version = !test_bit(CEPHFS_FEATURE_32BITS_RETRY_FWD, |
| 2919 | | − &session->s_features); |
| 2930 | + u16 request_head_version = mds_supported_head_version(session); |
| 2920 | 2931 | |
| 2921 | 2932 | ret = set_request_path_attr(mdsc, req->r_inode, req->r_dentry, |
| 2922 | 2933 | req->r_parent, req->r_path1, req->r_ino1.ino, |
| @@ -2957,8 +2968,10 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 34 unmodified lines |
| 2957 | 2968 | */ |
| 2958 | 2969 | if (legacy) |
| 2959 | 2970 | len = sizeof(struct ceph_mds_request_head_legacy); |
| 2960 | | − else if (old_version) |
| 2971 | + else if (request_head_version == 1) |
| 2961 | 2972 | len = sizeof(struct ceph_mds_request_head_old); |
| 2973 | + else if (request_head_version == 2) |
| 2974 | + len = offsetofend(struct ceph_mds_request_head, ext_num_fwd); |
| 2962 | 2975 | else |
| 2963 | 2976 | len = sizeof(struct ceph_mds_request_head); |
| 2964 | 2977 | |
| @@ -3008,6 +3021,18 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 43 unmodified lines |
| 3008 | 3021 | lhead = find_legacy_request_head(msg->front.iov_base, |
| 3009 | 3022 | session->s_con.peer_features); |
| 3010 | 3023 | |
| 3024 | + if ((req->r_mnt_idmap != &nop_mnt_idmap) && |
| 3025 | + !test_bit(CEPHFS_FEATURE_HAS_OWNER_UIDGID, &session->s_features)) { |
| 3026 | + WARN_ON_ONCE(!IS_CEPH_MDS_OP_NEWINODE(req->r_op)); |
| 3027 | + |
| 3028 | + pr_err_ratelimited_client(cl, |
| 3029 | + "idmapped mount is used and CEPHFS_FEATURE_HAS_OWNER_UIDGID" |
| 3030 | + " is not supported by MDS. Fail request with -EIO.\n"); |
| 3031 | + |
| 3032 | + ret = -EIO; |
| 3033 | + goto out_err; |
| 3034 | + } |
| 3035 | + |
| 3011 | 3036 | /* |
| 3012 | 3037 | * The ceph_mds_request_head_legacy didn't contain a version field, and |
| 3013 | 3038 | * one was added when we moved the message version from 3->4. |
| @@ -3015,17 +3040,40 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 1 unmodified line |
| 3015 | 3040 | if (legacy) { |
| 3016 | 3041 | msg->hdr.version = cpu_to_le16(3); |
| 3017 | 3042 | p = msg->front.iov_base + sizeof(*lhead); |
| 3018 | | − } else if (old_version) { |
| 3043 | + } else if (request_head_version == 1) { |
| 3019 | 3044 | struct ceph_mds_request_head_old *ohead = msg->front.iov_base; |
| 3020 | 3045 | |
| 3021 | 3046 | msg->hdr.version = cpu_to_le16(4); |
| 3022 | 3047 | ohead->version = cpu_to_le16(1); |
| 3023 | 3048 | p = msg->front.iov_base + sizeof(*ohead); |
| 3049 | + } else if (request_head_version == 2) { |
| 3050 | + struct ceph_mds_request_head *nhead = msg->front.iov_base; |
| 3051 | + |
| 3052 | + msg->hdr.version = cpu_to_le16(6); |
| 3053 | + nhead->version = cpu_to_le16(2); |
| 3054 | + |
| 3055 | + p = msg->front.iov_base + offsetofend(struct ceph_mds_request_head, ext_num_fwd); |
| 3024 | 3056 | } else { |
| 3025 | 3057 | struct ceph_mds_request_head *nhead = msg->front.iov_base; |
| 3058 | + kuid_t owner_fsuid; |
| 3059 | + kgid_t owner_fsgid; |
| 3026 | 3060 | |
| 3027 | 3061 | msg->hdr.version = cpu_to_le16(6); |
| 3028 | 3062 | nhead->version = cpu_to_le16(CEPH_MDS_REQUEST_HEAD_VERSION); |
| 3063 | + nhead->struct_len = cpu_to_le32(sizeof(struct ceph_mds_request_head)); |
| 3064 | + |
| 3065 | + if (IS_CEPH_MDS_OP_NEWINODE(req->r_op)) { |
| 3066 | + owner_fsuid = from_vfsuid(req->r_mnt_idmap, &init_user_ns, |
| 3067 | + VFSUIDT_INIT(req->r_cred->fsuid)); |
| 3068 | + owner_fsgid = from_vfsgid(req->r_mnt_idmap, &init_user_ns, |
| 3069 | + VFSGIDT_INIT(req->r_cred->fsgid)); |
| 3070 | + nhead->owner_uid = cpu_to_le32(from_kuid(&init_user_ns, owner_fsuid)); |
| 3071 | + nhead->owner_gid = cpu_to_le32(from_kgid(&init_user_ns, owner_fsgid)); |
| 3072 | + } else { |
| 3073 | + nhead->owner_uid = cpu_to_le32(-1); |
| 3074 | + nhead->owner_gid = cpu_to_le32(-1); |
| 3075 | + } |
| 3076 | + |
| 3029 | 3077 | p = msg->front.iov_base + sizeof(*nhead); |
| 3030 | 3078 | } |
| 3031 | 3079 | |