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