Whamcloud - gitweb
LU-3289 gss: Add Shared key and GSS Null functionality
[fs/lustre-release.git] / lustre / mdt / mdt_lib.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2015, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/mdt/mdt_lib.c
37  *
38  * Lustre Metadata Target (mdt) request unpacking helper.
39  *
40  * Author: Peter Braam <braam@clusterfs.com>
41  * Author: Andreas Dilger <adilger@clusterfs.com>
42  * Author: Phil Schwan <phil@clusterfs.com>
43  * Author: Mike Shaver <shaver@clusterfs.com>
44  * Author: Nikita Danilov <nikita@clusterfs.com>
45  * Author: Huang Hua <huanghua@clusterfs.com>
46  * Author: Fan Yong <fanyong@clusterfs.com>
47  */
48
49 #define DEBUG_SUBSYSTEM S_MDS
50
51 #include <linux/user_namespace.h>
52 #ifdef HAVE_UIDGID_HEADER
53 # include <linux/uidgid.h>
54 #endif
55 #include "mdt_internal.h"
56 #include <lnet/nidstr.h>
57 #include <lustre_nodemap.h>
58
59 typedef enum ucred_init_type {
60         NONE_INIT       = 0,
61         BODY_INIT       = 1,
62         REC_INIT        = 2
63 } ucred_init_type_t;
64
65 void mdt_exit_ucred(struct mdt_thread_info *info)
66 {
67         struct lu_ucred   *uc  = mdt_ucred(info);
68         struct mdt_device *mdt = info->mti_mdt;
69
70         LASSERT(uc != NULL);
71         if (uc->uc_valid != UCRED_INIT) {
72                 uc->uc_suppgids[0] = uc->uc_suppgids[1] = -1;
73                 if (uc->uc_ginfo) {
74                         put_group_info(uc->uc_ginfo);
75                         uc->uc_ginfo = NULL;
76                 }
77                 if (uc->uc_identity) {
78                         mdt_identity_put(mdt->mdt_identity_cache,
79                                          uc->uc_identity);
80                         uc->uc_identity = NULL;
81                 }
82                 uc->uc_valid = UCRED_INIT;
83         }
84 }
85
86 static int match_nosquash_list(struct rw_semaphore *sem,
87                                struct list_head *nidlist,
88                                lnet_nid_t peernid)
89 {
90         int rc;
91         ENTRY;
92         down_read(sem);
93         rc = cfs_match_nid(peernid, nidlist);
94         up_read(sem);
95         RETURN(rc);
96 }
97
98 /* root_squash for inter-MDS operations */
99 static int mdt_root_squash(struct mdt_thread_info *info, lnet_nid_t peernid)
100 {
101         struct lu_ucred *ucred = mdt_ucred(info);
102         struct root_squash_info *squash = &info->mti_mdt->mdt_squash;
103         ENTRY;
104
105         LASSERT(ucred != NULL);
106         if (!squash->rsi_uid || ucred->uc_fsuid)
107                 RETURN(0);
108
109         if (match_nosquash_list(&squash->rsi_sem,
110                                 &squash->rsi_nosquash_nids,
111                                 peernid)) {
112                 CDEBUG(D_OTHER, "%s is in nosquash_nids list\n",
113                        libcfs_nid2str(peernid));
114                 RETURN(0);
115         }
116
117         CDEBUG(D_OTHER, "squash req from %s, (%d:%d/%x)=>(%d:%d/%x)\n",
118                libcfs_nid2str(peernid),
119                ucred->uc_fsuid, ucred->uc_fsgid, ucred->uc_cap,
120                squash->rsi_uid, squash->rsi_gid, 0);
121
122         ucred->uc_fsuid = squash->rsi_uid;
123         ucred->uc_fsgid = squash->rsi_gid;
124         ucred->uc_cap = 0;
125         ucred->uc_suppgids[0] = -1;
126         ucred->uc_suppgids[1] = -1;
127
128         RETURN(0);
129 }
130
131 static void ucred_set_jobid(struct mdt_thread_info *info, struct lu_ucred *uc)
132 {
133         struct ptlrpc_request   *req = mdt_info_req(info);
134         const char              *jobid = mdt_req_get_jobid(req);
135
136         /* set jobid if specified. */
137         if (jobid)
138                 strlcpy(uc->uc_jobid, jobid, sizeof(uc->uc_jobid));
139         else
140                 uc->uc_jobid[0] = '\0';
141 }
142
143 static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
144                           void *buf, bool drop_fs_cap)
145 {
146         struct ptlrpc_request   *req = mdt_info_req(info);
147         struct mdt_device       *mdt = info->mti_mdt;
148         struct ptlrpc_user_desc *pud = req->rq_user_desc;
149         struct lu_ucred         *ucred = mdt_ucred(info);
150         lnet_nid_t               peernid = req->rq_peer.nid;
151         __u32                    perm = 0;
152         __u32                    remote = exp_connect_rmtclient(info->mti_exp);
153         int                      setuid;
154         int                      setgid;
155         int                      rc = 0;
156
157         ENTRY;
158
159         LASSERT(req->rq_auth_gss);
160         LASSERT(!req->rq_auth_usr_mdt);
161         LASSERT(req->rq_user_desc);
162         LASSERT(ucred != NULL);
163
164         ucred->uc_valid = UCRED_INVALID;
165
166         ucred->uc_o_uid   = pud->pud_uid;
167         ucred->uc_o_gid   = pud->pud_gid;
168         ucred->uc_o_fsuid = pud->pud_fsuid;
169         ucred->uc_o_fsgid = pud->pud_fsgid;
170
171         if (type == BODY_INIT) {
172                 struct mdt_body *body = (struct mdt_body *)buf;
173
174                 ucred->uc_suppgids[0] = body->mbo_suppgid;
175                 ucred->uc_suppgids[1] = -1;
176         }
177
178         /* sanity check: we expect the uid which client claimed is true */
179         if (remote) {
180                 if (!uid_valid(make_kuid(&init_user_ns, req->rq_auth_mapped_uid))) {
181                         CDEBUG(D_SEC, "remote user not mapped, deny access!\n");
182                         RETURN(-EACCES);
183                 }
184
185                 if (ptlrpc_user_desc_do_idmap(req, pud))
186                         RETURN(-EACCES);
187
188                 if (req->rq_auth_mapped_uid != pud->pud_uid) {
189                         CDEBUG(D_SEC, "remote client %s: auth/mapped uid %u/%u "
190                                "while client claims %u:%u/%u:%u\n",
191                                libcfs_nid2str(peernid), req->rq_auth_uid,
192                                req->rq_auth_mapped_uid,
193                                pud->pud_uid, pud->pud_gid,
194                                pud->pud_fsuid, pud->pud_fsgid);
195                         RETURN(-EACCES);
196                 }
197         } else {
198                 if (!flvr_is_rootonly(req->rq_flvr.sf_rpc) &&
199                     req->rq_auth_uid != pud->pud_uid) {
200                         CDEBUG(D_SEC, "local client %s: auth uid %u "
201                                "while client claims %u:%u/%u:%u\n",
202                                libcfs_nid2str(peernid), req->rq_auth_uid,
203                                pud->pud_uid, pud->pud_gid,
204                                pud->pud_fsuid, pud->pud_fsgid);
205                         RETURN(-EACCES);
206                 }
207         }
208
209         if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
210                 if (remote) {
211                         CDEBUG(D_SEC, "remote client must run with identity_get "
212                                "enabled!\n");
213                         RETURN(-EACCES);
214                 } else {
215                         ucred->uc_identity = NULL;
216                         perm = CFS_SETUID_PERM | CFS_SETGID_PERM |
217                                CFS_SETGRP_PERM;
218                 }
219         } else {
220                 struct md_identity *identity;
221
222                 identity = mdt_identity_get(mdt->mdt_identity_cache,
223                                             pud->pud_uid);
224                 if (IS_ERR(identity)) {
225                         if (unlikely(PTR_ERR(identity) == -EREMCHG &&
226                                      !remote)) {
227                                 ucred->uc_identity = NULL;
228                                 perm = CFS_SETUID_PERM | CFS_SETGID_PERM |
229                                        CFS_SETGRP_PERM;
230                         } else {
231                                 CDEBUG(D_SEC, "Deny access without identity: uid %u\n",
232                                        pud->pud_uid);
233                                 RETURN(-EACCES);
234                         }
235                 } else {
236                         ucred->uc_identity = identity;
237                         perm = mdt_identity_get_perm(ucred->uc_identity,
238                                                      remote, peernid);
239                 }
240         }
241
242         /* find out the setuid/setgid attempt */
243         setuid = (pud->pud_uid != pud->pud_fsuid);
244         setgid = ((pud->pud_gid != pud->pud_fsgid) ||
245                   (ucred->uc_identity &&
246                    (pud->pud_gid != ucred->uc_identity->mi_gid)));
247
248         /* check permission of setuid */
249         if (setuid && !(perm & CFS_SETUID_PERM)) {
250                 CDEBUG(D_SEC, "mdt blocked setuid attempt (%u -> %u) from %s\n",
251                        pud->pud_uid, pud->pud_fsuid, libcfs_nid2str(peernid));
252                 GOTO(out, rc = -EACCES);
253         }
254
255         /* check permission of setgid */
256         if (setgid && !(perm & CFS_SETGID_PERM)) {
257                 CDEBUG(D_SEC, "mdt blocked setgid attempt (%u:%u/%u:%u -> %u) "
258                        "from %s\n", pud->pud_uid, pud->pud_gid,
259                        pud->pud_fsuid, pud->pud_fsgid,
260                        ucred->uc_identity->mi_gid, libcfs_nid2str(peernid));
261                 GOTO(out, rc = -EACCES);
262         }
263
264         /*
265          * NB: remote client not allowed to setgroups anyway.
266          */
267         if (!remote && perm & CFS_SETGRP_PERM) {
268                 if (pud->pud_ngroups) {
269                         /* setgroups for local client */
270                         ucred->uc_ginfo = groups_alloc(pud->pud_ngroups);
271                         if (!ucred->uc_ginfo) {
272                                 CERROR("failed to alloc %d groups\n",
273                                        pud->pud_ngroups);
274                                 GOTO(out, rc = -ENOMEM);
275                         }
276
277                         lustre_groups_from_list(ucred->uc_ginfo,
278                                                 pud->pud_groups);
279                         lustre_groups_sort(ucred->uc_ginfo);
280                 } else {
281                         ucred->uc_ginfo = NULL;
282                 }
283         } else {
284                 ucred->uc_suppgids[0] = -1;
285                 ucred->uc_suppgids[1] = -1;
286                 ucred->uc_ginfo = NULL;
287         }
288
289         ucred->uc_uid   = pud->pud_uid;
290         ucred->uc_gid   = pud->pud_gid;
291         ucred->uc_fsuid = pud->pud_fsuid;
292         ucred->uc_fsgid = pud->pud_fsgid;
293
294         /* process root_squash here. */
295         mdt_root_squash(info, peernid);
296
297         /* remove fs privilege for non-root user. */
298         if (ucred->uc_fsuid && drop_fs_cap)
299                 ucred->uc_cap = pud->pud_cap & ~CFS_CAP_FS_MASK;
300         else
301                 ucred->uc_cap = pud->pud_cap;
302         if (remote && !(perm & CFS_RMTOWN_PERM))
303                 ucred->uc_cap &= ~(CFS_CAP_SYS_RESOURCE_MASK |
304                                    CFS_CAP_CHOWN_MASK);
305         ucred->uc_valid = UCRED_NEW;
306         ucred_set_jobid(info, ucred);
307
308         EXIT;
309
310 out:
311         if (rc) {
312                 if (ucred->uc_ginfo) {
313                         put_group_info(ucred->uc_ginfo);
314                         ucred->uc_ginfo = NULL;
315                 }
316                 if (ucred->uc_identity) {
317                         mdt_identity_put(mdt->mdt_identity_cache,
318                                          ucred->uc_identity);
319                         ucred->uc_identity = NULL;
320                 }
321         }
322
323         return rc;
324 }
325
326 /**
327  * Check whether allow the client to set supplementary group IDs or not.
328  *
329  * \param[in] info      pointer to the thread context
330  * \param[in] uc        pointer to the RPC user descriptor
331  *
332  * \retval              true if allow to set supplementary group IDs
333  * \retval              false for other cases
334  */
335 bool allow_client_chgrp(struct mdt_thread_info *info, struct lu_ucred *uc)
336 {
337         __u32 remote = exp_connect_rmtclient(info->mti_exp);
338         __u32 perm;
339
340         /* 1. If identity_upcall is disabled, then forbid remote client to set
341          *    supplementary group IDs, but permit local client to do that. */
342         if (is_identity_get_disabled(info->mti_mdt->mdt_identity_cache)) {
343                 if (remote)
344                         return false;
345
346                 return true;
347         }
348
349         /* 2. If fail to get related identities, then forbid any client to
350          *    set supplementary group IDs. */
351         if (uc->uc_identity == NULL)
352                 return false;
353
354         /* 3. Check the permission in the identities. */
355         perm = mdt_identity_get_perm(uc->uc_identity, remote,
356                                      mdt_info_req(info)->rq_peer.nid);
357         if (perm & CFS_SETGRP_PERM)
358                 return true;
359
360         return false;
361 }
362
363 int mdt_check_ucred(struct mdt_thread_info *info)
364 {
365         struct ptlrpc_request   *req = mdt_info_req(info);
366         struct mdt_device       *mdt = info->mti_mdt;
367         struct ptlrpc_user_desc *pud = req->rq_user_desc;
368         struct lu_ucred         *ucred = mdt_ucred(info);
369         struct md_identity      *identity = NULL;
370         lnet_nid_t               peernid = req->rq_peer.nid;
371         __u32                    perm = 0;
372         __u32                    remote = exp_connect_rmtclient(info->mti_exp);
373         int                      setuid;
374         int                      setgid;
375         int                      rc = 0;
376
377         ENTRY;
378
379         LASSERT(ucred != NULL);
380         if ((ucred->uc_valid == UCRED_OLD) || (ucred->uc_valid == UCRED_NEW))
381                 RETURN(0);
382
383         if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc)
384                 RETURN(0);
385
386         /* sanity check: if we use strong authentication, we expect the
387          * uid which client claimed is true */
388         if (remote) {
389                 if (!uid_valid(make_kuid(&init_user_ns, req->rq_auth_mapped_uid))) {
390                         CDEBUG(D_SEC, "remote user not mapped, deny access!\n");
391                         RETURN(-EACCES);
392                 }
393
394                 if (ptlrpc_user_desc_do_idmap(req, pud))
395                         RETURN(-EACCES);
396
397                 if (req->rq_auth_mapped_uid != pud->pud_uid) {
398                         CDEBUG(D_SEC, "remote client %s: auth/mapped uid %u/%u "
399                                "while client claims %u:%u/%u:%u\n",
400                                libcfs_nid2str(peernid), req->rq_auth_uid,
401                                req->rq_auth_mapped_uid,
402                                pud->pud_uid, pud->pud_gid,
403                                pud->pud_fsuid, pud->pud_fsgid);
404                         RETURN(-EACCES);
405                 }
406         } else {
407                 if (!flvr_is_rootonly(req->rq_flvr.sf_rpc) &&
408                     req->rq_auth_uid != pud->pud_uid) {
409                         CDEBUG(D_SEC, "local client %s: auth uid %u "
410                                "while client claims %u:%u/%u:%u\n",
411                                libcfs_nid2str(peernid), req->rq_auth_uid,
412                                pud->pud_uid, pud->pud_gid,
413                                pud->pud_fsuid, pud->pud_fsgid);
414                         RETURN(-EACCES);
415                 }
416         }
417
418         if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
419                 if (remote) {
420                         CDEBUG(D_SEC, "remote client must run with identity_get "
421                                "enabled!\n");
422                         RETURN(-EACCES);
423                 }
424                 RETURN(0);
425         }
426
427         identity = mdt_identity_get(mdt->mdt_identity_cache, pud->pud_uid);
428         if (IS_ERR(identity)) {
429                 if (unlikely(PTR_ERR(identity) == -EREMCHG &&
430                              !remote)) {
431                         RETURN(0);
432                 } else {
433                         CDEBUG(D_SEC, "Deny access without identity: uid %u\n",
434                                pud->pud_uid);
435                         RETURN(-EACCES);
436                }
437         }
438
439         perm = mdt_identity_get_perm(identity, remote, peernid);
440         /* find out the setuid/setgid attempt */
441         setuid = (pud->pud_uid != pud->pud_fsuid);
442         setgid = (pud->pud_gid != pud->pud_fsgid ||
443                   pud->pud_gid != identity->mi_gid);
444
445         /* check permission of setuid */
446         if (setuid && !(perm & CFS_SETUID_PERM)) {
447                 CDEBUG(D_SEC, "mdt blocked setuid attempt (%u -> %u) from %s\n",
448                        pud->pud_uid, pud->pud_fsuid, libcfs_nid2str(peernid));
449                 GOTO(out, rc = -EACCES);
450         }
451
452         /* check permission of setgid */
453         if (setgid && !(perm & CFS_SETGID_PERM)) {
454                 CDEBUG(D_SEC, "mdt blocked setgid attempt (%u:%u/%u:%u -> %u) "
455                        "from %s\n", pud->pud_uid, pud->pud_gid,
456                        pud->pud_fsuid, pud->pud_fsgid, identity->mi_gid,
457                        libcfs_nid2str(peernid));
458                 GOTO(out, rc = -EACCES);
459         }
460
461         EXIT;
462
463 out:
464         mdt_identity_put(mdt->mdt_identity_cache, identity);
465         return rc;
466 }
467
468 static int old_init_ucred_common(struct mdt_thread_info *info,
469                                  struct lu_nodemap *nodemap,
470                                  bool drop_fs_cap)
471 {
472         struct lu_ucred         *uc = mdt_ucred(info);
473         struct mdt_device       *mdt = info->mti_mdt;
474         struct md_identity      *identity = NULL;
475
476         if (!is_identity_get_disabled(mdt->mdt_identity_cache)) {
477                 identity = mdt_identity_get(mdt->mdt_identity_cache,
478                                             uc->uc_fsuid);
479                 if (IS_ERR(identity)) {
480                         if (unlikely(PTR_ERR(identity) == -EREMCHG ||
481                                      uc->uc_cap & CFS_CAP_FS_MASK)) {
482                                 identity = NULL;
483                         } else {
484                                 CDEBUG(D_SEC, "Deny access without identity: "
485                                        "uid %u\n", uc->uc_fsuid);
486                                 RETURN(-EACCES);
487                         }
488                 }
489         }
490         uc->uc_identity = identity;
491
492         if (nodemap && uc->uc_o_uid == nodemap->nm_squash_uid) {
493                 uc->uc_fsuid = nodemap->nm_squash_uid;
494                 uc->uc_fsgid = nodemap->nm_squash_gid;
495                 uc->uc_cap = 0;
496                 uc->uc_suppgids[0] = -1;
497                 uc->uc_suppgids[1] = -1;
498         }
499
500         /* process root_squash here. */
501         mdt_root_squash(info, mdt_info_req(info)->rq_peer.nid);
502
503         /* remove fs privilege for non-root user. */
504         if (uc->uc_fsuid && drop_fs_cap)
505                 uc->uc_cap &= ~CFS_CAP_FS_MASK;
506         uc->uc_valid = UCRED_OLD;
507         ucred_set_jobid(info, uc);
508
509         return 0;
510 }
511
512 static int old_init_ucred(struct mdt_thread_info *info,
513                           struct mdt_body *body, bool drop_fs_cap)
514 {
515         struct lu_ucred *uc = mdt_ucred(info);
516         struct lu_nodemap *nodemap;
517         int rc;
518         ENTRY;
519
520         nodemap = nodemap_get_from_exp(info->mti_exp);
521         if (IS_ERR(nodemap))
522                 RETURN(PTR_ERR(nodemap));
523
524         body->mbo_uid = nodemap_map_id(nodemap, NODEMAP_UID,
525                                        NODEMAP_CLIENT_TO_FS, body->mbo_uid);
526         body->mbo_gid = nodemap_map_id(nodemap, NODEMAP_GID,
527                                        NODEMAP_CLIENT_TO_FS, body->mbo_gid);
528         body->mbo_fsuid = nodemap_map_id(nodemap, NODEMAP_UID,
529                                        NODEMAP_CLIENT_TO_FS, body->mbo_fsuid);
530         body->mbo_fsgid = nodemap_map_id(nodemap, NODEMAP_GID,
531                                        NODEMAP_CLIENT_TO_FS, body->mbo_fsgid);
532
533         LASSERT(uc != NULL);
534         uc->uc_valid = UCRED_INVALID;
535         uc->uc_o_uid = uc->uc_uid = body->mbo_uid;
536         uc->uc_o_gid = uc->uc_gid = body->mbo_gid;
537         uc->uc_o_fsuid = uc->uc_fsuid = body->mbo_fsuid;
538         uc->uc_o_fsgid = uc->uc_fsgid = body->mbo_fsgid;
539         uc->uc_suppgids[0] = body->mbo_suppgid;
540         uc->uc_suppgids[1] = -1;
541         uc->uc_ginfo = NULL;
542         uc->uc_cap = body->mbo_capability;
543
544         rc = old_init_ucred_common(info, nodemap, drop_fs_cap);
545         nodemap_putref(nodemap);
546
547         RETURN(rc);
548 }
549
550 static int old_init_ucred_reint(struct mdt_thread_info *info)
551 {
552         struct lu_ucred *uc = mdt_ucred(info);
553         struct lu_nodemap *nodemap;
554         int rc;
555         ENTRY;
556
557         nodemap = nodemap_get_from_exp(info->mti_exp);
558         if (IS_ERR(nodemap))
559                 RETURN(PTR_ERR(nodemap));
560
561         LASSERT(uc != NULL);
562
563         uc->uc_fsuid = nodemap_map_id(nodemap, NODEMAP_UID,
564                                       NODEMAP_CLIENT_TO_FS, uc->uc_fsuid);
565         uc->uc_fsgid = nodemap_map_id(nodemap, NODEMAP_GID,
566                                       NODEMAP_CLIENT_TO_FS, uc->uc_fsgid);
567
568         uc->uc_valid = UCRED_INVALID;
569         uc->uc_o_uid = uc->uc_o_fsuid = uc->uc_uid = uc->uc_fsuid;
570         uc->uc_o_gid = uc->uc_o_fsgid = uc->uc_gid = uc->uc_fsgid;
571         uc->uc_ginfo = NULL;
572
573         rc = old_init_ucred_common(info, nodemap, true); /* drop_fs_cap=true */
574         nodemap_putref(nodemap);
575
576         RETURN(rc);
577 }
578
579 static inline int __mdt_init_ucred(struct mdt_thread_info *info,
580                                    struct mdt_body *body,
581                                    bool drop_fs_cap)
582 {
583         struct ptlrpc_request   *req = mdt_info_req(info);
584         struct lu_ucred         *uc  = mdt_ucred(info);
585
586         LASSERT(uc != NULL);
587         if ((uc->uc_valid == UCRED_OLD) || (uc->uc_valid == UCRED_NEW))
588                 return 0;
589
590         mdt_exit_ucred(info);
591
592         if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc)
593                 return old_init_ucred(info, body, drop_fs_cap);
594         else
595                 return new_init_ucred(info, BODY_INIT, body, drop_fs_cap);
596 }
597
598 int mdt_init_ucred(struct mdt_thread_info *info, struct mdt_body *body)
599 {
600         return __mdt_init_ucred(info, body, true);
601 }
602
603 /* LU-6528 when "no_subtree_check" is set for NFS export, nfsd_set_fh_dentry()
604  * doesn't set correct fsuid explicitely, but raise capability to allow
605  * exportfs_decode_fh() to reconnect disconnected dentry into dcache. So for
606  * lookup (i.e. intent_getattr), we should keep FS capability, otherwise it
607  * will fail permission check. */
608 int mdt_init_ucred_intent_getattr(struct mdt_thread_info *info,
609                                   struct mdt_body *body)
610 {
611         return __mdt_init_ucred(info, body, false);
612 }
613
614 int mdt_init_ucred_reint(struct mdt_thread_info *info)
615 {
616         struct ptlrpc_request *req = mdt_info_req(info);
617         struct lu_ucred       *uc  = mdt_ucred(info);
618
619         LASSERT(uc != NULL);
620         if ((uc->uc_valid == UCRED_OLD) || (uc->uc_valid == UCRED_NEW))
621                 return 0;
622
623         mdt_exit_ucred(info);
624
625         if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc)
626                 return old_init_ucred_reint(info);
627         else
628                 return new_init_ucred(info, REC_INIT, NULL, true);
629 }
630
631 /* copied from lov/lov_ea.c, just for debugging, will be removed later */
632 void mdt_dump_lmm(int level, const struct lov_mds_md *lmm, __u64 valid)
633 {
634         const struct lov_ost_data_v1    *lod;
635         int                              i;
636         __u16                            count;
637
638         if (likely(!cfs_cdebug_show(level, DEBUG_SUBSYSTEM)))
639                 return;
640
641         count = le16_to_cpu(((struct lov_user_md *)lmm)->lmm_stripe_count);
642
643         CDEBUG(level, "objid "DOSTID", magic 0x%08X, pattern %#X\n",
644                POSTID(&lmm->lmm_oi), le32_to_cpu(lmm->lmm_magic),
645                le32_to_cpu(lmm->lmm_pattern));
646         CDEBUG(level, "stripe_size=0x%x, stripe_count=0x%x\n",
647                le32_to_cpu(lmm->lmm_stripe_size), count);
648
649         /* If it's a directory or a released file, then there are
650          * no actual objects to print, so bail out. */
651         if (valid & OBD_MD_FLDIREA ||
652             le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED)
653                 return;
654
655         LASSERT(count <= LOV_MAX_STRIPE_COUNT);
656         for (i = 0, lod = lmm->lmm_objects; i < count; i++, lod++) {
657                 struct ost_id oi;
658
659                 ostid_le_to_cpu(&lod->l_ost_oi, &oi);
660                 CDEBUG(level, "stripe %u idx %u subobj "DOSTID"\n",
661                        i, le32_to_cpu(lod->l_ost_idx), POSTID(&oi));
662         }
663 }
664
665 void mdt_dump_lmv(unsigned int level, const union lmv_mds_md *lmv)
666 {
667         const struct lmv_mds_md_v1 *lmm1;
668         int                        i;
669
670         if (likely(!cfs_cdebug_show(level, DEBUG_SUBSYSTEM)))
671                 return;
672
673         lmm1 = &lmv->lmv_md_v1;
674         CDEBUG(level, "magic 0x%08X, master %#X stripe_count %#x\n",
675                le32_to_cpu(lmm1->lmv_magic),
676                le32_to_cpu(lmm1->lmv_master_mdt_index),
677                le32_to_cpu(lmm1->lmv_stripe_count));
678
679         if (le32_to_cpu(lmm1->lmv_magic) == LMV_MAGIC_STRIPE)
680                 return;
681
682         for (i = 0; i < le32_to_cpu(lmm1->lmv_stripe_count); i++) {
683                 struct lu_fid fid;
684
685                 fid_le_to_cpu(&fid, &lmm1->lmv_stripe_fids[i]);
686                 CDEBUG(level, "idx %u subobj "DFID"\n", i, PFID(&fid));
687         }
688 }
689
690 /* Shrink and/or grow reply buffers */
691 int mdt_fix_reply(struct mdt_thread_info *info)
692 {
693         struct req_capsule *pill = info->mti_pill;
694         struct mdt_body    *body;
695         int                md_size, md_packed = 0;
696         int                acl_size;
697         int                rc = 0;
698         ENTRY;
699
700         body = req_capsule_server_get(pill, &RMF_MDT_BODY);
701         LASSERT(body != NULL);
702
703         if (body->mbo_valid & (OBD_MD_FLDIREA | OBD_MD_FLEASIZE |
704                                OBD_MD_LINKNAME))
705                 md_size = body->mbo_eadatasize;
706         else
707                 md_size = 0;
708
709         acl_size = body->mbo_aclsize;
710
711         /* this replay - not send info to client */
712         if (info->mti_spec.no_create) {
713                 md_size = 0;
714                 acl_size = 0;
715         }
716
717         CDEBUG(D_INFO, "Shrink to md_size = %d cookie/acl_size = %d\n",
718                md_size, acl_size);
719 /*
720             &RMF_MDT_BODY,
721             &RMF_MDT_MD,
722             &RMF_ACL, or &RMF_LOGCOOKIES
723 (optional)  &RMF_CAPA1,
724 (optional)  &RMF_CAPA2,
725 (optional)  something else
726 */
727
728         /* MDT_MD buffer may be bigger than packed value, let's shrink all
729          * buffers before growing it */
730         if (info->mti_big_lmm_used) {
731                 /* big_lmm buffer may be used even without packing the result
732                  * into reply, just for internal server needs */
733                 if (req_capsule_has_field(pill, &RMF_MDT_MD, RCL_SERVER))
734                         md_packed = req_capsule_get_size(pill, &RMF_MDT_MD,
735                                                          RCL_SERVER);
736
737                 /* free big lmm if md_size is not needed */
738                 if (md_size == 0 || md_packed == 0) {
739                         info->mti_big_lmm_used = 0;
740                 } else {
741                         /* buffer must be allocated separately */
742                         LASSERT(info->mti_attr.ma_lmm !=
743                                 req_capsule_server_get(pill, &RMF_MDT_MD));
744                         req_capsule_shrink(pill, &RMF_MDT_MD, 0, RCL_SERVER);
745                 }
746         } else if (req_capsule_has_field(pill, &RMF_MDT_MD, RCL_SERVER)) {
747                 req_capsule_shrink(pill, &RMF_MDT_MD, md_size, RCL_SERVER);
748         }
749
750         if (req_capsule_has_field(pill, &RMF_ACL, RCL_SERVER))
751                 req_capsule_shrink(pill, &RMF_ACL, acl_size, RCL_SERVER);
752         else if (req_capsule_has_field(pill, &RMF_LOGCOOKIES, RCL_SERVER))
753                 req_capsule_shrink(pill, &RMF_LOGCOOKIES,
754                                    acl_size, RCL_SERVER);
755
756         if (req_capsule_has_field(pill, &RMF_CAPA1, RCL_SERVER) &&
757             !(body->mbo_valid & OBD_MD_FLMDSCAPA))
758                 req_capsule_shrink(pill, &RMF_CAPA1, 0, RCL_SERVER);
759
760         if (req_capsule_has_field(pill, &RMF_CAPA2, RCL_SERVER) &&
761             !(body->mbo_valid & OBD_MD_FLOSSCAPA))
762                 req_capsule_shrink(pill, &RMF_CAPA2, 0, RCL_SERVER);
763
764         /*
765          * Some more field should be shrinked if needed.
766          * This should be done by those who added fields to reply message.
767          */
768
769         /* Grow MD buffer if needed finally */
770         if (info->mti_big_lmm_used) {
771                 void *lmm;
772
773                 LASSERT(md_size > md_packed);
774                 CDEBUG(D_INFO, "Enlarge reply buffer, need extra %d bytes\n",
775                        md_size - md_packed);
776                 rc = req_capsule_server_grow(pill, &RMF_MDT_MD, md_size);
777                 if (rc) {
778                         /* we can't answer with proper LOV EA, drop flags,
779                          * the rc is also returned so this request is
780                          * considered as failed */
781                         body->mbo_valid &= ~(OBD_MD_FLDIREA | OBD_MD_FLEASIZE);
782                         /* don't return transno along with error */
783                         lustre_msg_set_transno(pill->rc_req->rq_repmsg, 0);
784                 } else {
785                         /* now we need to pack right LOV/LMV EA */
786                         lmm = req_capsule_server_get(pill, &RMF_MDT_MD);
787                         if (info->mti_attr.ma_valid & MA_LOV) {
788                                 LASSERT(req_capsule_get_size(pill, &RMF_MDT_MD,
789                                                              RCL_SERVER) ==
790                                                 info->mti_attr.ma_lmm_size);
791                                 memcpy(lmm, info->mti_attr.ma_lmm,
792                                        info->mti_attr.ma_lmm_size);
793                         } else if (info->mti_attr.ma_valid & MA_LMV) {
794                                 LASSERT(req_capsule_get_size(pill, &RMF_MDT_MD,
795                                                              RCL_SERVER) ==
796                                                 info->mti_attr.ma_lmv_size);
797                                 memcpy(lmm, info->mti_attr.ma_lmv,
798                                        info->mti_attr.ma_lmv_size);
799                         }
800                 }
801                 /* update mdt_max_mdsize so clients will be aware about that */
802                 if (info->mti_mdt->mdt_max_mdsize < info->mti_attr.ma_lmm_size)
803                         info->mti_mdt->mdt_max_mdsize =
804                                                     info->mti_attr.ma_lmm_size;
805                 info->mti_big_lmm_used = 0;
806         }
807         RETURN(rc);
808 }
809
810
811 /* if object is dying, pack the lov/llog data,
812  * parameter info->mti_attr should be valid at this point! */
813 int mdt_handle_last_unlink(struct mdt_thread_info *info, struct mdt_object *mo,
814                            const struct md_attr *ma)
815 {
816         struct mdt_body       *repbody;
817         const struct lu_attr *la = &ma->ma_attr;
818         ENTRY;
819
820         repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY);
821         LASSERT(repbody != NULL);
822
823         if (ma->ma_valid & MA_INODE)
824                 mdt_pack_attr2body(info, repbody, la, mdt_object_fid(mo));
825
826         if (ma->ma_valid & MA_LOV) {
827                 CERROR("No need in LOV EA upon unlink\n");
828                 dump_stack();
829         }
830         repbody->mbo_eadatasize = 0;
831
832         RETURN(0);
833 }
834
835 static __u64 mdt_attr_valid_xlate(__u64 in, struct mdt_reint_record *rr,
836                                   struct md_attr *ma)
837 {
838         __u64 out;
839
840         out = 0;
841         if (in & MDS_ATTR_MODE)
842                 out |= LA_MODE;
843         if (in & MDS_ATTR_UID)
844                 out |= LA_UID;
845         if (in & MDS_ATTR_GID)
846                 out |= LA_GID;
847         if (in & MDS_ATTR_SIZE)
848                 out |= LA_SIZE;
849         if (in & MDS_ATTR_BLOCKS)
850                 out |= LA_BLOCKS;
851         if (in & MDS_ATTR_ATIME_SET)
852                 out |= LA_ATIME;
853         if (in & MDS_ATTR_CTIME_SET)
854                 out |= LA_CTIME;
855         if (in & MDS_ATTR_MTIME_SET)
856                 out |= LA_MTIME;
857         if (in & MDS_ATTR_ATTR_FLAG)
858                 out |= LA_FLAGS;
859         if (in & MDS_ATTR_KILL_SUID)
860                 out |= LA_KILL_SUID;
861         if (in & MDS_ATTR_KILL_SGID)
862                 out |= LA_KILL_SGID;
863
864         if (in & MDS_ATTR_FROM_OPEN)
865                 rr->rr_flags |= MRF_OPEN_TRUNC;
866         if (in & MDS_OPEN_OWNEROVERRIDE)
867                 ma->ma_attr_flags |= MDS_OWNEROVERRIDE;
868         if (in & MDS_ATTR_FORCE)
869                 ma->ma_attr_flags |= MDS_PERM_BYPASS;
870
871         in &= ~(MDS_ATTR_MODE | MDS_ATTR_UID | MDS_ATTR_GID |
872                 MDS_ATTR_ATIME | MDS_ATTR_MTIME | MDS_ATTR_CTIME |
873                 MDS_ATTR_ATIME_SET | MDS_ATTR_CTIME_SET | MDS_ATTR_MTIME_SET |
874                 MDS_ATTR_SIZE | MDS_ATTR_BLOCKS | MDS_ATTR_ATTR_FLAG |
875                 MDS_ATTR_FORCE | MDS_ATTR_KILL_SUID | MDS_ATTR_KILL_SGID |
876                 MDS_ATTR_FROM_OPEN | MDS_OPEN_OWNEROVERRIDE);
877         if (in != 0)
878                 CERROR("Unknown attr bits: "LPX64"\n", in);
879         return out;
880 }
881
882 /* unpacking */
883
884 int mdt_name_unpack(struct req_capsule *pill,
885                     const struct req_msg_field *field,
886                     struct lu_name *ln,
887                     enum mdt_name_flags flags)
888 {
889         ln->ln_name = req_capsule_client_get(pill, field);
890         ln->ln_namelen = req_capsule_get_size(pill, field, RCL_CLIENT) - 1;
891
892         if (!lu_name_is_valid(ln)) {
893                 ln->ln_name = NULL;
894                 ln->ln_namelen = 0;
895
896                 return -EPROTO;
897         }
898
899         if ((flags & MNF_FIX_ANON) &&
900             ln->ln_namelen == 1 && ln->ln_name[0] == '/') {
901                 /* Newer (3.x) kernels use a name of "/" for the
902                  * "anonymous" disconnected dentries from NFS
903                  * filehandle conversion. See d_obtain_alias(). */
904                 ln->ln_name = NULL;
905                 ln->ln_namelen = 0;
906         }
907
908         return 0;
909 }
910
911 static int mdt_setattr_unpack_rec(struct mdt_thread_info *info)
912 {
913         struct lu_ucred         *uc = mdt_ucred(info);
914         struct md_attr          *ma = &info->mti_attr;
915         struct lu_attr          *la = &ma->ma_attr;
916         struct req_capsule      *pill = info->mti_pill;
917         struct mdt_reint_record *rr = &info->mti_rr;
918         struct mdt_rec_setattr  *rec;
919         struct lu_nodemap       *nodemap;
920         ENTRY;
921
922         CLASSERT(sizeof(struct mdt_rec_setattr)== sizeof(struct mdt_rec_reint));
923         rec = req_capsule_client_get(pill, &RMF_REC_REINT);
924         if (rec == NULL)
925                 RETURN(-EFAULT);
926
927         /* This prior initialization is needed for old_init_ucred_reint() */
928         uc->uc_fsuid = rec->sa_fsuid;
929         uc->uc_fsgid = rec->sa_fsgid;
930         uc->uc_cap   = rec->sa_cap;
931         uc->uc_suppgids[0] = rec->sa_suppgid;
932         uc->uc_suppgids[1] = -1;
933
934         rr->rr_fid1 = &rec->sa_fid;
935         la->la_valid = mdt_attr_valid_xlate(rec->sa_valid, rr, ma);
936         la->la_mode  = rec->sa_mode;
937         la->la_flags = rec->sa_attr_flags;
938
939         nodemap = nodemap_get_from_exp(info->mti_exp);
940         if (IS_ERR(nodemap))
941                 RETURN(PTR_ERR(nodemap));
942
943         la->la_uid   = nodemap_map_id(nodemap, NODEMAP_UID,
944                                       NODEMAP_CLIENT_TO_FS, rec->sa_uid);
945         la->la_gid   = nodemap_map_id(nodemap, NODEMAP_GID,
946                                       NODEMAP_CLIENT_TO_FS, rec->sa_gid);
947         nodemap_putref(nodemap);
948
949         la->la_size  = rec->sa_size;
950         la->la_blocks = rec->sa_blocks;
951         la->la_ctime = rec->sa_ctime;
952         la->la_atime = rec->sa_atime;
953         la->la_mtime = rec->sa_mtime;
954         ma->ma_valid = MA_INODE;
955
956         if (rec->sa_bias & MDS_DATA_MODIFIED)
957                 ma->ma_attr_flags |= MDS_DATA_MODIFIED;
958         else
959                 ma->ma_attr_flags &= ~MDS_DATA_MODIFIED;
960
961         if (rec->sa_bias & MDS_HSM_RELEASE)
962                 ma->ma_attr_flags |= MDS_HSM_RELEASE;
963         else
964                 ma->ma_attr_flags &= ~MDS_HSM_RELEASE;
965
966         if (rec->sa_bias & MDS_CLOSE_LAYOUT_SWAP)
967                 ma->ma_attr_flags |= MDS_CLOSE_LAYOUT_SWAP;
968         else
969                 ma->ma_attr_flags &= ~MDS_CLOSE_LAYOUT_SWAP;
970
971         RETURN(0);
972 }
973
974 static int mdt_close_handle_unpack(struct mdt_thread_info *info)
975 {
976         struct req_capsule *pill = info->mti_pill;
977         struct mdt_ioepoch *ioepoch;
978         ENTRY;
979
980         if (req_capsule_get_size(pill, &RMF_MDT_EPOCH, RCL_CLIENT))
981                 ioepoch = req_capsule_client_get(pill, &RMF_MDT_EPOCH);
982         else
983                 ioepoch = NULL;
984
985         if (ioepoch == NULL)
986                 RETURN(-EPROTO);
987
988         info->mti_close_handle = ioepoch->mio_handle;
989
990         RETURN(0);
991 }
992
993 static inline int mdt_dlmreq_unpack(struct mdt_thread_info *info) {
994         struct req_capsule      *pill = info->mti_pill;
995
996         if (req_capsule_get_size(pill, &RMF_DLM_REQ, RCL_CLIENT)) {
997                 info->mti_dlm_req = req_capsule_client_get(pill, &RMF_DLM_REQ);
998                 if (info->mti_dlm_req == NULL)
999                         RETURN(-EFAULT);
1000         }
1001
1002         RETURN(0);
1003 }
1004
1005 static int mdt_setattr_unpack(struct mdt_thread_info *info)
1006 {
1007         struct mdt_reint_record *rr = &info->mti_rr;
1008         struct md_attr          *ma = &info->mti_attr;
1009         struct req_capsule      *pill = info->mti_pill;
1010         int rc;
1011         ENTRY;
1012
1013         rc = mdt_setattr_unpack_rec(info);
1014         if (rc)
1015                 RETURN(rc);
1016
1017         if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) {
1018                 rr->rr_eadata = req_capsule_client_get(pill, &RMF_EADATA);
1019                 rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA,
1020                                                         RCL_CLIENT);
1021                 if (rr->rr_eadatalen > 0) {
1022                         const struct lmv_user_md        *lum;
1023
1024                         lum = rr->rr_eadata;
1025                         /* Sigh ma_valid(from req) does not indicate whether
1026                          * it will set LOV/LMV EA, so we have to check magic */
1027                         if (le32_to_cpu(lum->lum_magic) == LMV_USER_MAGIC) {
1028                                 ma->ma_valid |= MA_LMV;
1029                                 ma->ma_lmv = (void *)rr->rr_eadata;
1030                                 ma->ma_lmv_size = rr->rr_eadatalen;
1031                         } else {
1032                                 ma->ma_valid |= MA_LOV;
1033                                 ma->ma_lmm = (void *)rr->rr_eadata;
1034                                 ma->ma_lmm_size = rr->rr_eadatalen;
1035                         }
1036                 }
1037         }
1038
1039         rc = mdt_dlmreq_unpack(info);
1040         RETURN(rc);
1041 }
1042
1043 static int mdt_intent_close_unpack(struct mdt_thread_info *info)
1044 {
1045         struct md_attr          *ma = &info->mti_attr;
1046         struct req_capsule      *pill = info->mti_pill;
1047         ENTRY;
1048
1049         if (!(ma->ma_attr_flags & (MDS_HSM_RELEASE | MDS_CLOSE_LAYOUT_SWAP)))
1050                 RETURN(0);
1051
1052         req_capsule_extend(pill, &RQF_MDS_INTENT_CLOSE);
1053
1054         if (!(req_capsule_has_field(pill, &RMF_CLOSE_DATA, RCL_CLIENT) &&
1055             req_capsule_field_present(pill, &RMF_CLOSE_DATA, RCL_CLIENT)))
1056                 RETURN(-EFAULT);
1057
1058         RETURN(0);
1059 }
1060
1061 int mdt_close_unpack(struct mdt_thread_info *info)
1062 {
1063         int rc;
1064         ENTRY;
1065
1066         rc = mdt_close_handle_unpack(info);
1067         if (rc)
1068                 RETURN(rc);
1069
1070         rc = mdt_setattr_unpack_rec(info);
1071         if (rc)
1072                 RETURN(rc);
1073
1074         rc = mdt_intent_close_unpack(info);
1075         if (rc)
1076                 RETURN(rc);
1077
1078         RETURN(mdt_init_ucred_reint(info));
1079 }
1080
1081 static int mdt_create_unpack(struct mdt_thread_info *info)
1082 {
1083         struct lu_ucred         *uc  = mdt_ucred(info);
1084         struct mdt_rec_create   *rec;
1085         struct lu_attr          *attr = &info->mti_attr.ma_attr;
1086         struct mdt_reint_record *rr = &info->mti_rr;
1087         struct req_capsule      *pill = info->mti_pill;
1088         struct md_op_spec       *sp = &info->mti_spec;
1089         int rc;
1090         ENTRY;
1091
1092         CLASSERT(sizeof(struct mdt_rec_create) == sizeof(struct mdt_rec_reint));
1093         rec = req_capsule_client_get(pill, &RMF_REC_REINT);
1094         if (rec == NULL)
1095                 RETURN(-EFAULT);
1096
1097         /* This prior initialization is needed for old_init_ucred_reint() */
1098         uc->uc_fsuid = rec->cr_fsuid;
1099         uc->uc_fsgid = rec->cr_fsgid;
1100         uc->uc_cap   = rec->cr_cap;
1101         uc->uc_suppgids[0] = rec->cr_suppgid1;
1102         uc->uc_suppgids[1] = -1;
1103         uc->uc_umask = rec->cr_umask;
1104
1105         rr->rr_fid1 = &rec->cr_fid1;
1106         rr->rr_fid2 = &rec->cr_fid2;
1107         attr->la_mode = rec->cr_mode;
1108         attr->la_rdev  = rec->cr_rdev;
1109         attr->la_uid   = rec->cr_fsuid;
1110         attr->la_gid   = rec->cr_fsgid;
1111         attr->la_ctime = rec->cr_time;
1112         attr->la_mtime = rec->cr_time;
1113         attr->la_atime = rec->cr_time;
1114         attr->la_valid = LA_MODE | LA_RDEV | LA_UID | LA_GID | LA_TYPE |
1115                          LA_CTIME | LA_MTIME | LA_ATIME;
1116         memset(&sp->u, 0, sizeof(sp->u));
1117         sp->sp_cr_flags = get_mrc_cr_flags(rec);
1118
1119         rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0);
1120         if (rc < 0)
1121                 RETURN(rc);
1122
1123         if (S_ISLNK(attr->la_mode)) {
1124                 const char *tgt = NULL;
1125
1126                 req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_SYM);
1127                 if (req_capsule_get_size(pill, &RMF_SYMTGT, RCL_CLIENT)) {
1128                         tgt = req_capsule_client_get(pill, &RMF_SYMTGT);
1129                         sp->u.sp_symname = tgt;
1130                 }
1131                 if (tgt == NULL)
1132                         RETURN(-EFAULT);
1133         } else {
1134                 req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_RMT_ACL);
1135                 if (S_ISDIR(attr->la_mode) &&
1136                     req_capsule_get_size(pill, &RMF_EADATA, RCL_CLIENT) > 0) {
1137                         sp->u.sp_ea.eadata =
1138                                 req_capsule_client_get(pill, &RMF_EADATA);
1139                         sp->u.sp_ea.eadatalen =
1140                                 req_capsule_get_size(pill, &RMF_EADATA,
1141                                                      RCL_CLIENT);
1142                         sp->sp_cr_flags |= MDS_OPEN_HAS_EA;
1143                 }
1144         }
1145
1146         rc = mdt_dlmreq_unpack(info);
1147         RETURN(rc);
1148 }
1149
1150 static int mdt_link_unpack(struct mdt_thread_info *info)
1151 {
1152         struct lu_ucred         *uc  = mdt_ucred(info);
1153         struct mdt_rec_link     *rec;
1154         struct lu_attr          *attr = &info->mti_attr.ma_attr;
1155         struct mdt_reint_record *rr = &info->mti_rr;
1156         struct req_capsule      *pill = info->mti_pill;
1157         int rc;
1158         ENTRY;
1159
1160         CLASSERT(sizeof(struct mdt_rec_link) == sizeof(struct mdt_rec_reint));
1161         rec = req_capsule_client_get(pill, &RMF_REC_REINT);
1162         if (rec == NULL)
1163                 RETURN(-EFAULT);
1164
1165         /* This prior initialization is needed for old_init_ucred_reint() */
1166         uc->uc_fsuid = rec->lk_fsuid;
1167         uc->uc_fsgid = rec->lk_fsgid;
1168         uc->uc_cap   = rec->lk_cap;
1169         uc->uc_suppgids[0] = rec->lk_suppgid1;
1170         uc->uc_suppgids[1] = rec->lk_suppgid2;
1171
1172         attr->la_uid = rec->lk_fsuid;
1173         attr->la_gid = rec->lk_fsgid;
1174         rr->rr_fid1 = &rec->lk_fid1;
1175         rr->rr_fid2 = &rec->lk_fid2;
1176         attr->la_ctime = rec->lk_time;
1177         attr->la_mtime = rec->lk_time;
1178         attr->la_valid = LA_UID | LA_GID | LA_CTIME | LA_MTIME;
1179
1180         rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0);
1181         if (rc < 0)
1182                 RETURN(rc);
1183
1184         rc = mdt_dlmreq_unpack(info);
1185
1186         RETURN(rc);
1187 }
1188
1189 static int mdt_unlink_unpack(struct mdt_thread_info *info)
1190 {
1191         struct lu_ucred         *uc  = mdt_ucred(info);
1192         struct mdt_rec_unlink   *rec;
1193         struct md_attr          *ma = &info->mti_attr;
1194         struct lu_attr          *attr = &info->mti_attr.ma_attr;
1195         struct mdt_reint_record *rr = &info->mti_rr;
1196         struct req_capsule      *pill = info->mti_pill;
1197         int rc;
1198         ENTRY;
1199
1200         CLASSERT(sizeof(struct mdt_rec_unlink) == sizeof(struct mdt_rec_reint));
1201         rec = req_capsule_client_get(pill, &RMF_REC_REINT);
1202         if (rec == NULL)
1203                 RETURN(-EFAULT);
1204
1205         /* This prior initialization is needed for old_init_ucred_reint() */
1206         uc->uc_fsuid = rec->ul_fsuid;
1207         uc->uc_fsgid = rec->ul_fsgid;
1208         uc->uc_cap   = rec->ul_cap;
1209         uc->uc_suppgids[0] = rec->ul_suppgid1;
1210         uc->uc_suppgids[1] = -1;
1211
1212         attr->la_uid = rec->ul_fsuid;
1213         attr->la_gid = rec->ul_fsgid;
1214         rr->rr_fid1 = &rec->ul_fid1;
1215         rr->rr_fid2 = &rec->ul_fid2;
1216         attr->la_ctime = rec->ul_time;
1217         attr->la_mtime = rec->ul_time;
1218         attr->la_mode  = rec->ul_mode;
1219         attr->la_valid = LA_UID | LA_GID | LA_CTIME | LA_MTIME | LA_MODE;
1220
1221         rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0);
1222         if (rc < 0)
1223                 RETURN(rc);
1224
1225         if (rec->ul_bias & MDS_VTX_BYPASS)
1226                 ma->ma_attr_flags |= MDS_VTX_BYPASS;
1227         else
1228                 ma->ma_attr_flags &= ~MDS_VTX_BYPASS;
1229
1230         info->mti_spec.no_create = !!req_is_replay(mdt_info_req(info));
1231
1232         rc = mdt_dlmreq_unpack(info);
1233         RETURN(rc);
1234 }
1235
1236 static int mdt_rmentry_unpack(struct mdt_thread_info *info)
1237 {
1238         info->mti_spec.sp_rm_entry = 1;
1239         return mdt_unlink_unpack(info);
1240 }
1241
1242 static int mdt_rename_unpack(struct mdt_thread_info *info)
1243 {
1244         struct lu_ucred         *uc = mdt_ucred(info);
1245         struct mdt_rec_rename   *rec;
1246         struct md_attr          *ma = &info->mti_attr;
1247         struct lu_attr          *attr = &info->mti_attr.ma_attr;
1248         struct mdt_reint_record *rr = &info->mti_rr;
1249         struct req_capsule      *pill = info->mti_pill;
1250         int rc;
1251         ENTRY;
1252
1253         CLASSERT(sizeof(struct mdt_rec_rename) == sizeof(struct mdt_rec_reint));
1254         rec = req_capsule_client_get(pill, &RMF_REC_REINT);
1255         if (rec == NULL)
1256                 RETURN(-EFAULT);
1257
1258         /* This prior initialization is needed for old_init_ucred_reint() */
1259         uc->uc_fsuid = rec->rn_fsuid;
1260         uc->uc_fsgid = rec->rn_fsgid;
1261         uc->uc_cap   = rec->rn_cap;
1262         uc->uc_suppgids[0] = rec->rn_suppgid1;
1263         uc->uc_suppgids[1] = rec->rn_suppgid2;
1264
1265         attr->la_uid = rec->rn_fsuid;
1266         attr->la_gid = rec->rn_fsgid;
1267         rr->rr_fid1 = &rec->rn_fid1;
1268         rr->rr_fid2 = &rec->rn_fid2;
1269         attr->la_ctime = rec->rn_time;
1270         attr->la_mtime = rec->rn_time;
1271         /* rename_tgt contains the mode already */
1272         attr->la_mode = rec->rn_mode;
1273         attr->la_valid = LA_UID | LA_GID | LA_CTIME | LA_MTIME | LA_MODE;
1274
1275         rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0);
1276         if (rc < 0)
1277                 RETURN(rc);
1278
1279         rc = mdt_name_unpack(pill, &RMF_SYMTGT, &rr->rr_tgt_name, 0);
1280         if (rc < 0)
1281                 RETURN(rc);
1282
1283         if (rec->rn_bias & MDS_VTX_BYPASS)
1284                 ma->ma_attr_flags |= MDS_VTX_BYPASS;
1285         else
1286                 ma->ma_attr_flags &= ~MDS_VTX_BYPASS;
1287
1288         if (rec->rn_bias & MDS_RENAME_MIGRATE) {
1289                 req_capsule_extend(info->mti_pill, &RQF_MDS_REINT_MIGRATE);
1290                 rc = mdt_close_handle_unpack(info);
1291                 if (rc < 0)
1292                         RETURN(rc);
1293                 info->mti_spec.sp_migrate_close = 1;
1294         }
1295
1296         info->mti_spec.no_create = !!req_is_replay(mdt_info_req(info));
1297
1298
1299         rc = mdt_dlmreq_unpack(info);
1300
1301         RETURN(rc);
1302 }
1303
1304 /*
1305  * please see comment above LOV_MAGIC_V1_DEF
1306  */
1307 static void mdt_fix_lov_magic(struct mdt_thread_info *info)
1308 {
1309         struct mdt_reint_record *rr = &info->mti_rr;
1310         struct lov_user_md_v1   *v1;
1311
1312         v1 = (void *)rr->rr_eadata;
1313         LASSERT(v1);
1314
1315         if (unlikely(req_is_replay(mdt_info_req(info)))) {
1316                 if (v1->lmm_magic == LOV_USER_MAGIC_V1) {
1317                         v1->lmm_magic = LOV_MAGIC_V1_DEF;
1318                 } else if (v1->lmm_magic == __swab32(LOV_USER_MAGIC_V1)) {
1319                         v1->lmm_magic = __swab32(LOV_MAGIC_V1_DEF);
1320                 } else if (v1->lmm_magic == LOV_USER_MAGIC_V3) {
1321                         v1->lmm_magic = LOV_MAGIC_V3_DEF;
1322                 } else if (v1->lmm_magic == __swab32(LOV_USER_MAGIC_V3)) {
1323                         v1->lmm_magic = __swab32(LOV_MAGIC_V3_DEF);
1324                 }
1325         }
1326 }
1327
1328 static int mdt_open_unpack(struct mdt_thread_info *info)
1329 {
1330         struct lu_ucred         *uc = mdt_ucred(info);
1331         struct mdt_rec_create   *rec;
1332         struct lu_attr          *attr = &info->mti_attr.ma_attr;
1333         struct req_capsule      *pill = info->mti_pill;
1334         struct mdt_reint_record *rr   = &info->mti_rr;
1335         struct ptlrpc_request   *req  = mdt_info_req(info);
1336         struct md_op_spec       *sp   = &info->mti_spec;
1337         ENTRY;
1338
1339         CLASSERT(sizeof(struct mdt_rec_create) == sizeof(struct mdt_rec_reint));
1340         rec = req_capsule_client_get(pill, &RMF_REC_REINT);
1341         if (rec == NULL)
1342                 RETURN(-EFAULT);
1343
1344         /* This prior initialization is needed for old_init_ucred_reint() */
1345         uc->uc_fsuid = rec->cr_fsuid;
1346         uc->uc_fsgid = rec->cr_fsgid;
1347         uc->uc_cap   = rec->cr_cap;
1348         uc->uc_suppgids[0] = rec->cr_suppgid1;
1349         uc->uc_suppgids[1] = rec->cr_suppgid2;
1350         uc->uc_umask = rec->cr_umask;
1351
1352         rr->rr_fid1   = &rec->cr_fid1;
1353         rr->rr_fid2   = &rec->cr_fid2;
1354         rr->rr_handle = &rec->cr_old_handle;
1355         attr->la_mode = rec->cr_mode;
1356         attr->la_rdev  = rec->cr_rdev;
1357         attr->la_uid   = rec->cr_fsuid;
1358         attr->la_gid   = rec->cr_fsgid;
1359         attr->la_ctime = rec->cr_time;
1360         attr->la_mtime = rec->cr_time;
1361         attr->la_atime = rec->cr_time;
1362         attr->la_valid = LA_MODE  | LA_RDEV  | LA_UID   | LA_GID |
1363                          LA_CTIME | LA_MTIME | LA_ATIME;
1364         memset(&info->mti_spec.u, 0, sizeof(info->mti_spec.u));
1365         info->mti_spec.sp_cr_flags = get_mrc_cr_flags(rec);
1366         /* Do not trigger ASSERTION if client miss to set such flags. */
1367         if (unlikely(info->mti_spec.sp_cr_flags == 0))
1368                 RETURN(-EPROTO);
1369
1370         info->mti_cross_ref = !!(rec->cr_bias & MDS_CROSS_REF);
1371
1372         mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, MNF_FIX_ANON);
1373
1374         if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) {
1375                 rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA,
1376                                                         RCL_CLIENT);
1377                 if (rr->rr_eadatalen > 0) {
1378                         rr->rr_eadata = req_capsule_client_get(pill,
1379                                                                &RMF_EADATA);
1380                         sp->u.sp_ea.eadatalen = rr->rr_eadatalen;
1381                         sp->u.sp_ea.eadata = rr->rr_eadata;
1382                         sp->no_create = !!req_is_replay(req);
1383                         mdt_fix_lov_magic(info);
1384                 }
1385
1386                 /*
1387                  * Client default md_size may be 0 right after client start,
1388                  * until all osc are connected, set here just some reasonable
1389                  * value to prevent misbehavior.
1390                  */
1391                 if (rr->rr_eadatalen == 0 &&
1392                     !(info->mti_spec.sp_cr_flags & MDS_OPEN_DELAY_CREATE))
1393                         rr->rr_eadatalen = MIN_MD_SIZE;
1394         }
1395
1396         RETURN(0);
1397 }
1398
1399 static int mdt_setxattr_unpack(struct mdt_thread_info *info)
1400 {
1401         struct mdt_reint_record *rr     = &info->mti_rr;
1402         struct lu_ucred         *uc     = mdt_ucred(info);
1403         struct lu_attr          *attr   = &info->mti_attr.ma_attr;
1404         struct req_capsule      *pill   = info->mti_pill;
1405         struct mdt_rec_setxattr *rec;
1406         int                      rc;
1407         ENTRY;
1408
1409
1410         CLASSERT(sizeof(struct mdt_rec_setxattr) ==
1411                          sizeof(struct mdt_rec_reint));
1412
1413         rec = req_capsule_client_get(pill, &RMF_REC_REINT);
1414         if (rec == NULL)
1415                 RETURN(-EFAULT);
1416
1417         /* This prior initialization is needed for old_init_ucred_reint() */
1418         uc->uc_fsuid  = rec->sx_fsuid;
1419         uc->uc_fsgid  = rec->sx_fsgid;
1420         uc->uc_cap    = rec->sx_cap;
1421         uc->uc_suppgids[0] = rec->sx_suppgid1;
1422         uc->uc_suppgids[1] = -1;
1423
1424         rr->rr_opcode = rec->sx_opcode;
1425         rr->rr_fid1   = &rec->sx_fid;
1426         attr->la_valid = rec->sx_valid;
1427         attr->la_ctime = rec->sx_time;
1428         attr->la_size = rec->sx_size;
1429         attr->la_flags = rec->sx_flags;
1430
1431         rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0);
1432         if (rc < 0)
1433                 RETURN(rc);
1434
1435         if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) {
1436                 rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA,
1437                                                         RCL_CLIENT);
1438                 if (rr->rr_eadatalen > 0) {
1439                         rr->rr_eadata = req_capsule_client_get(pill,
1440                                                                &RMF_EADATA);
1441                         if (rr->rr_eadata == NULL)
1442                                 RETURN(-EFAULT);
1443                 } else {
1444                         rr->rr_eadata = NULL;
1445                 }
1446         } else if (!(attr->la_valid & OBD_MD_FLXATTRRM)) {
1447                 CDEBUG(D_INFO, "no xattr data supplied\n");
1448                 RETURN(-EFAULT);
1449         }
1450
1451         if (mdt_dlmreq_unpack(info) < 0)
1452                 RETURN(-EPROTO);
1453
1454         RETURN(0);
1455 }
1456
1457
1458 typedef int (*reint_unpacker)(struct mdt_thread_info *info);
1459
1460 static reint_unpacker mdt_reint_unpackers[REINT_MAX] = {
1461         [REINT_SETATTR]  = mdt_setattr_unpack,
1462         [REINT_CREATE]   = mdt_create_unpack,
1463         [REINT_LINK]     = mdt_link_unpack,
1464         [REINT_UNLINK]   = mdt_unlink_unpack,
1465         [REINT_RENAME]   = mdt_rename_unpack,
1466         [REINT_OPEN]     = mdt_open_unpack,
1467         [REINT_SETXATTR] = mdt_setxattr_unpack,
1468         [REINT_RMENTRY]  = mdt_rmentry_unpack,
1469         [REINT_MIGRATE]  = mdt_rename_unpack,
1470 };
1471
1472 int mdt_reint_unpack(struct mdt_thread_info *info, __u32 op)
1473 {
1474         int rc;
1475         ENTRY;
1476
1477         memset(&info->mti_rr, 0, sizeof(info->mti_rr));
1478         if (op < REINT_MAX && mdt_reint_unpackers[op] != NULL) {
1479                 info->mti_rr.rr_opcode = op;
1480                 rc = mdt_reint_unpackers[op](info);
1481         } else {
1482                 CERROR("Unexpected opcode %d\n", op);
1483                 rc = -EFAULT;
1484         }
1485         RETURN(rc);
1486 }