Whamcloud - gitweb
01793a54b31c1ddbd7007b91846575aa5c696bd5
[fs/lustre-release.git] / lustre / mdt / mdt_lib.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/mdt/mdt_lib.c
5  *  Lustre Metadata Target (mdt) request unpacking helper.
6  *
7  *  Copyright (c) 2006 Cluster File Systems, Inc.
8  *   Author: Peter Braam <braam@clusterfs.com>
9  *   Author: Andreas Dilger <adilger@clusterfs.com>
10  *   Author: Phil Schwan <phil@clusterfs.com>
11  *   Author: Mike Shaver <shaver@clusterfs.com>
12  *   Author: Nikita Danilov <nikita@clusterfs.com>
13  *   Author: Huang Hua <huanghua@clusterfs.com>
14  *
15  *
16  *   This file is part of the Lustre file system, http://www.lustre.org
17  *   Lustre is a trademark of Cluster File Systems, Inc.
18  *
19  *   You may have signed or agreed to another license before downloading
20  *   this software.  If so, you are bound by the terms and conditions
21  *   of that agreement, and the following does not apply to you.  See the
22  *   LICENSE file included with this distribution for more information.
23  *
24  *   If you did not agree to a different license, then this copy of Lustre
25  *   is open source software; you can redistribute it and/or modify it
26  *   under the terms of version 2 of the GNU General Public License as
27  *   published by the Free Software Foundation.
28  *
29  *   In either case, Lustre is distributed in the hope that it will be
30  *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
31  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32  *   license text for more details.
33  */
34
35
36 #ifndef EXPORT_SYMTAB
37 # define EXPORT_SYMTAB
38 #endif
39 #define DEBUG_SUBSYSTEM S_MDS
40
41 #include "mdt_internal.h"
42
43
44 typedef enum ucred_init_type {
45         NONE_INIT       = 0,
46         BODY_INIT       = 1,
47         REC_INIT        = 2
48 } ucred_init_type_t;
49
50 int groups_from_list(struct group_info *ginfo, gid_t *glist)
51 {
52         int i;
53         int count = ginfo->ngroups;
54
55         /* fill group_info from gid array */
56         for (i = 0; i < ginfo->nblocks; i++) {
57                 int cp_count = min(NGROUPS_PER_BLOCK, count);
58                 int off = i * NGROUPS_PER_BLOCK;
59                 int len = cp_count * sizeof(*glist);
60
61                 if (memcpy(ginfo->blocks[i], glist + off, len))
62                         return -EFAULT;
63
64                 count -= cp_count;
65         }
66         return 0;
67 }
68
69 /* groups_sort() is copied from linux kernel! */
70 /* a simple shell-metzner sort */
71 void groups_sort(struct group_info *group_info)
72 {
73         int base, max, stride;
74         int gidsetsize = group_info->ngroups;
75
76         for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
77                 ; /* nothing */
78         stride /= 3;
79
80         while (stride) {
81                 max = gidsetsize - stride;
82                 for (base = 0; base < max; base++) {
83                         int left = base;
84                         int right = left + stride;
85                         gid_t tmp = GROUP_AT(group_info, right);
86
87                         while (left >= 0 && GROUP_AT(group_info, left) > tmp) {
88                                 GROUP_AT(group_info, right) =
89                                     GROUP_AT(group_info, left);
90                                 right = left;
91                                 left -= stride;
92                         }
93                         GROUP_AT(group_info, right) = tmp;
94                 }
95                 stride /= 3;
96         }
97 }
98
99 void mdt_exit_ucred(struct mdt_thread_info *info)
100 {
101         struct md_ucred   *uc  = mdt_ucred(info);
102         struct mdt_device *mdt = info->mti_mdt;
103
104         if (uc->mu_valid != UCRED_INIT) {
105                 uc->mu_suppgids[0] = uc->mu_suppgids[1] = -1;
106                 if (uc->mu_ginfo) {
107                         groups_free(uc->mu_ginfo);
108                         uc->mu_ginfo = NULL;
109                 }
110                 if (uc->mu_identity) {
111                         mdt_identity_put(mdt->mdt_identity_cache,
112                                          uc->mu_identity);
113                         uc->mu_identity = NULL;
114                 }
115                 uc->mu_valid = UCRED_INIT;
116         }
117 }
118
119 static int old_init_ucred(struct mdt_thread_info *info,
120                           struct mdt_body *body)
121 {
122         struct md_ucred     *uc  = mdt_ucred(info);
123         struct mdt_device   *mdt = info->mti_mdt;
124         struct mdt_identity *identity = NULL;
125
126         ENTRY;
127
128         uc->mu_valid = UCRED_INVALID;
129
130         if (!is_identity_get_disabled(mdt->mdt_identity_cache)) {
131                 /* get identity info of this user */
132                 identity = mdt_identity_get(mdt->mdt_identity_cache,
133                                             body->fsuid);
134                 if (!identity) {
135                         CERROR("Deny access without identity: uid %d\n",
136                                body->fsuid);
137                         RETURN(-EACCES);
138                 }
139         }
140
141         uc->mu_valid = UCRED_OLD;
142         uc->mu_squash = SQUASH_NONE;
143         uc->mu_o_uid = uc->mu_uid = body->uid;
144         uc->mu_o_gid = uc->mu_gid = body->gid;
145         uc->mu_o_fsuid = uc->mu_fsuid = body->fsuid;
146         uc->mu_o_fsgid = uc->mu_fsgid = body->fsgid;
147         uc->mu_suppgids[0] = body->suppgid;
148         uc->mu_suppgids[1] = -1;
149         if (uc->mu_fsuid)
150                 uc->mu_cap = body->capability & ~CAP_FS_MASK;
151         else
152                 uc->mu_cap = body->capability;
153         uc->mu_ginfo = NULL;
154         uc->mu_identity = identity;
155
156         RETURN(0);
157 }
158
159 static int old_init_ucred_reint(struct mdt_thread_info *info)
160 {
161         struct md_ucred     *uc  = mdt_ucred(info);
162         struct mdt_device   *mdt = info->mti_mdt;
163         struct mdt_identity *identity = NULL;
164
165         ENTRY;
166
167         uc->mu_valid = UCRED_INVALID;
168
169         if (!is_identity_get_disabled(mdt->mdt_identity_cache)) {
170                 /* get identity info of this user */
171                 identity = mdt_identity_get(mdt->mdt_identity_cache,
172                                             uc->mu_fsuid);
173                 if (!identity) {
174                         CERROR("Deny access without identity: uid %d\n",
175                                uc->mu_fsuid);
176                         RETURN(-EACCES);
177                 }
178         }
179
180         uc->mu_valid = UCRED_OLD;
181         uc->mu_squash = SQUASH_NONE;
182         uc->mu_o_uid = uc->mu_o_fsuid = uc->mu_uid = uc->mu_fsuid;
183         uc->mu_o_gid = uc->mu_o_fsgid = uc->mu_gid = uc->mu_fsgid;
184         if (uc->mu_fsuid)
185                 uc->mu_cap &= ~CAP_FS_MASK;
186         uc->mu_ginfo = NULL;
187         uc->mu_identity = identity;
188
189         RETURN(0);
190 }
191
192 static int nid_nosquash(struct mdt_device *mdt, lnet_nid_t nid)
193 {
194         struct rootsquash_info *rsi = mdt->mdt_rootsquash_info;
195         int i;
196
197         for (i = 0; i < rsi->rsi_n_nosquash_nids; i++)
198                 if ((rsi->rsi_nosquash_nids[i] == nid) ||
199                     (rsi->rsi_nosquash_nids[i] == LNET_NID_ANY))
200                         return 1;
201
202         return 0;
203 }
204
205 static int mdt_squash_root(struct mdt_device *mdt, struct md_ucred *ucred,
206                            struct ptlrpc_user_desc *pud, lnet_nid_t peernid)
207 {
208         struct rootsquash_info *rsi = mdt->mdt_rootsquash_info;
209
210         if (!rsi || (!rsi->rsi_uid && !rsi->rsi_gid) ||
211             nid_nosquash(mdt, peernid))
212                 return 0;
213
214         CDEBUG(D_SEC, "squash req from "LPX64":"
215                "(%u:%u-%u:%u/%x)=>(%u:%u-%u:%u/%x)\n", peernid,
216                pud->pud_uid, pud->pud_gid,
217                pud->pud_fsuid, pud->pud_fsgid, pud->pud_cap,
218                pud->pud_uid ? pud->pud_uid : rsi->rsi_uid,
219                pud->pud_uid ? pud->pud_gid : rsi->rsi_gid,
220                pud->pud_fsuid ? pud->pud_fsuid : rsi->rsi_uid,
221                pud->pud_fsuid ? pud->pud_fsgid : rsi->rsi_gid,
222                pud->pud_cap & ~CAP_FS_MASK);
223
224         if (rsi->rsi_uid) {
225                 if (!pud->pud_uid) {
226                         ucred->mu_uid = rsi->rsi_uid;
227                         ucred->mu_squash |= SQUASH_UID;
228                 } else {
229                         ucred->mu_uid = pud->pud_uid;
230                 }
231
232                 if (!pud->pud_fsuid) {
233                         ucred->mu_fsuid = rsi->rsi_uid;
234                         ucred->mu_squash |= SQUASH_UID;
235                 } else {
236                         ucred->mu_fsuid = pud->pud_fsuid;
237                 }
238         } else {
239                 ucred->mu_uid   = pud->pud_uid;
240                 ucred->mu_fsuid = pud->pud_fsuid;
241         }
242
243         if (rsi->rsi_gid) {
244                 int i;
245
246                 if (!pud->pud_gid) {
247                         ucred->mu_gid = rsi->rsi_gid;
248                         ucred->mu_squash |= SQUASH_GID;
249                 } else {
250                         ucred->mu_gid = pud->pud_gid;
251                 }
252
253                 if (!pud->pud_fsgid) {
254                         ucred->mu_fsgid = rsi->rsi_gid;
255                         ucred->mu_squash |= SQUASH_GID;
256                 } else {
257                         ucred->mu_fsgid = pud->pud_fsgid;
258                 }
259
260                 for (i = 0; i < 2; i++) {
261                         if (!ucred->mu_suppgids[i]) {
262                                 ucred->mu_suppgids[i] = rsi->rsi_gid;
263                                 ucred->mu_squash |= SQUASH_GID;
264                         }
265                 }
266
267                 for (i = 0; i < pud->pud_ngroups; i++) {
268                         if (!pud->pud_groups[i]) {
269                                 pud->pud_groups[i] = rsi->rsi_gid;
270                                 ucred->mu_squash |= SQUASH_GID;
271                         }
272                 }
273         } else {
274                 ucred->mu_gid   = pud->pud_gid;
275                 ucred->mu_fsgid = pud->pud_fsgid;
276         }
277
278         return 1;
279 }
280
281 static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
282                           void *buf)
283 {
284         struct ptlrpc_request   *req = mdt_info_req(info);
285         struct mdt_export_data  *med = mdt_req2med(req);
286         struct mdt_device       *mdt = info->mti_mdt;
287         struct ptlrpc_user_desc *pud = req->rq_user_desc;
288         struct md_ucred         *ucred = mdt_ucred(info);
289         struct mdt_identity     *identity = NULL;
290         lnet_nid_t              peernid = req->rq_peer.nid;
291         __u32                   setxid_perm = 0;
292         int                     setuid;
293         int                     setgid;
294         int                     rc = 0;
295
296         ENTRY;
297
298         LASSERT(req->rq_auth_gss);
299         LASSERT(!req->rq_auth_usr_mdt);
300         LASSERT(req->rq_user_desc);
301         
302         ucred->mu_valid = UCRED_INVALID;
303
304         ucred->mu_o_uid   = pud->pud_uid;
305         ucred->mu_o_gid   = pud->pud_gid;
306         ucred->mu_o_fsuid = pud->pud_fsuid;
307         ucred->mu_o_fsgid = pud->pud_fsgid;
308
309         if (type == BODY_INIT) {
310                 struct mdt_body *body = (struct mdt_body *)buf;
311
312                 ucred->mu_suppgids[0] = body->suppgid;
313                 ucred->mu_suppgids[1] = -1;
314         }
315
316         /* sanity check: we expect the uid which client claimed is true */
317         if (med->med_rmtclient) {
318                 if (req->rq_auth_mapped_uid == INVALID_UID) {
319                         CWARN("remote user not mapped, deny access!\n");
320                         RETURN(-EACCES);
321                 }
322
323                 if (ptlrpc_user_desc_do_idmap(req, pud))
324                         RETURN(-EACCES);
325
326                 if (req->rq_auth_mapped_uid != pud->pud_uid) {
327                         CERROR("remote client "LPU64": auth uid %u "
328                                "while client claim %u:%u/%u:%u\n",
329                                peernid, req->rq_auth_uid, pud->pud_uid,
330                                pud->pud_gid, pud->pud_fsuid, pud->pud_fsgid);
331                         RETURN(-EACCES);
332                 }
333         } else {
334                 if (req->rq_auth_uid != pud->pud_uid) {
335                         CERROR("local client "LPU64": auth uid %u "
336                                "while client claim %u:%u/%u:%u\n",
337                                peernid, req->rq_auth_uid, pud->pud_uid,
338                                pud->pud_gid, pud->pud_fsuid, pud->pud_fsgid);
339                         RETURN(-EACCES);
340                 }
341         }
342
343         if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
344                 if (med->med_rmtclient) {
345                         CERROR("remote client must run with identity_get "
346                                "enabled!\n");
347                         RETURN(-EACCES);
348                 } else {
349                         setxid_perm |= LUSTRE_SETGRP_PERM;
350                         goto check_squash;
351                 }
352         }
353
354         identity = mdt_identity_get(mdt->mdt_identity_cache, pud->pud_uid);
355         if (!identity) {
356                 CERROR("Deny access without identity: uid %d\n", pud->pud_uid);
357                 RETURN(-EACCES);
358         }
359
360         setxid_perm = mdt_identity_get_setxid_perm(identity,
361                                                    med->med_rmtclient,
362                                                    peernid);
363
364         /* find out the setuid/setgid attempt */
365         setuid = (pud->pud_uid != pud->pud_fsuid);
366         setgid = (pud->pud_gid != pud->pud_fsgid ||
367                   pud->pud_gid != identity->mi_gid);
368
369         /* check permission of setuid */
370         if (setuid && !(setxid_perm & LUSTRE_SETUID_PERM)) {
371                 CWARN("mdt blocked setuid attempt (%u -> %u) from "
372                       LPX64"\n", pud->pud_uid, pud->pud_fsuid, peernid);
373                 GOTO(out, rc = -EACCES);
374         }
375
376         /* check permission of setgid */
377         if (setgid && !(setxid_perm & LUSTRE_SETGID_PERM)) {
378                 CWARN("mdt blocked setgid attempt (%u:%u/%u:%u -> %u) "
379                       "from "LPX64"\n", pud->pud_uid, pud->pud_gid,
380                       pud->pud_fsuid, pud->pud_fsgid, identity->mi_gid,
381                       peernid);
382                 GOTO(out, rc = -EACCES);
383         }
384
385 check_squash:
386         /* FIXME: The exact behavior of root_squash is not defined. */
387         ucred->mu_squash = SQUASH_NONE;
388         if (mdt_squash_root(mdt, ucred, pud, peernid) == 0) {
389                 ucred->mu_uid   = pud->pud_uid;
390                 ucred->mu_gid   = pud->pud_gid;
391                 ucred->mu_fsuid = pud->pud_fsuid;
392                 ucred->mu_fsgid = pud->pud_fsgid;
393         }
394
395         /* remove fs privilege for non-root user */
396         if (ucred->mu_fsuid)
397                 ucred->mu_cap = pud->pud_cap & ~CAP_FS_MASK;
398         else
399                 ucred->mu_cap = pud->pud_cap;
400
401         /*
402          * NB: remote client not allowed to setgroups anyway.
403          */
404         if (!med->med_rmtclient && pud->pud_ngroups &&
405             (setxid_perm & LUSTRE_SETGRP_PERM)) {
406                 struct group_info *ginfo;
407
408                 /* setgroups for local client */
409                 ginfo = groups_alloc(pud->pud_ngroups);
410                 if (!ginfo) {
411                         CERROR("failed to alloc %d groups\n",
412                                pud->pud_ngroups);
413                         GOTO(out, rc = -ENOMEM);
414                 }
415                 groups_from_list(ginfo, pud->pud_groups);
416                 groups_sort(ginfo);
417                 ucred->mu_ginfo = ginfo;
418         } else {
419                 ucred->mu_ginfo = NULL;
420         }
421
422         ucred->mu_identity = identity;
423         ucred->mu_valid = UCRED_NEW;
424
425         EXIT;
426
427 out:
428         if (rc && identity)
429                 mdt_identity_put(mdt->mdt_identity_cache, identity);
430
431         return rc;
432 }
433
434 int mdt_check_ucred(struct mdt_thread_info *info)
435 {
436         struct ptlrpc_request   *req = mdt_info_req(info);
437         struct mdt_export_data  *med = mdt_req2med(req);
438         struct mdt_device       *mdt = info->mti_mdt;
439         struct ptlrpc_user_desc *pud = req->rq_user_desc;
440         struct md_ucred         *ucred = mdt_ucred(info);
441         struct mdt_identity     *identity;
442         lnet_nid_t              peernid = req->rq_peer.nid;
443
444         ENTRY;
445
446         if ((ucred->mu_valid == UCRED_OLD) || (ucred->mu_valid == UCRED_NEW))
447                 RETURN(0);
448
449         if (!req->rq_user_desc)
450                 RETURN(0);
451
452         /* sanity check: if we use strong authentication, we expect the
453          * uid which client claimed is true */
454         if (req->rq_auth_gss) {
455                 if (med->med_rmtclient) {
456                         if (req->rq_auth_mapped_uid == INVALID_UID) {
457                                 CWARN("remote user not mapped, deny access!\n");
458                                 RETURN(-EACCES);
459                         }
460
461                         if (ptlrpc_user_desc_do_idmap(req, pud))
462                                 RETURN(-EACCES);
463
464                         if (req->rq_auth_mapped_uid != pud->pud_uid) {
465                                 CERROR("remote client "LPU64": auth uid %u "
466                                        "while client claim %u:%u/%u:%u\n",
467                                        peernid, req->rq_auth_uid, pud->pud_uid,
468                                        pud->pud_gid, pud->pud_fsuid,
469                                        pud->pud_fsgid);
470                                 RETURN(-EACCES);
471                         }
472                 } else {
473                         if (req->rq_auth_uid != pud->pud_uid) {
474                                 CERROR("local client "LPU64": auth uid %u "
475                                        "while client claim %u:%u/%u:%u\n",
476                                        peernid, req->rq_auth_uid, pud->pud_uid,
477                                        pud->pud_gid, pud->pud_fsuid,
478                                        pud->pud_fsgid);
479                                 RETURN(-EACCES);
480                         }
481                 }
482         }
483
484         if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
485                 if (med->med_rmtclient) {
486                         CERROR("remote client must run with "
487                                "identity_get enabled!\n");
488                         RETURN(-EACCES);
489                 }
490         } else {
491                 identity = mdt_identity_get(mdt->mdt_identity_cache,
492                                             pud->pud_uid);
493                 if (!identity) {
494                         CERROR("Deny access without identity: uid %d\n",
495                                pud->pud_uid);
496                         RETURN(-EACCES);
497                 }
498
499                 mdt_identity_put(mdt->mdt_identity_cache, identity);
500         }
501
502         RETURN(0);
503 }
504
505 int mdt_init_ucred(struct mdt_thread_info *info, struct mdt_body *body)
506 {
507         struct ptlrpc_request *req = mdt_info_req(info);
508         struct md_ucred       *uc  = mdt_ucred(info);
509
510         if ((uc->mu_valid == UCRED_OLD) || (uc->mu_valid == UCRED_NEW))
511                 return 0;
512
513         mdt_exit_ucred(info);
514
515         if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc)
516                 return old_init_ucred(info, body);
517         else
518                 return new_init_ucred(info, BODY_INIT, body);
519 }
520
521 int mdt_init_ucred_reint(struct mdt_thread_info *info)
522 {
523         struct ptlrpc_request *req = mdt_info_req(info);
524         struct md_ucred       *uc  = mdt_ucred(info);
525
526         if ((uc->mu_valid == UCRED_OLD) || (uc->mu_valid == UCRED_NEW))
527                 return 0;
528
529         mdt_exit_ucred(info);
530
531         if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc)
532                 return old_init_ucred_reint(info);
533         else
534                 return new_init_ucred(info, REC_INIT, NULL);
535 }
536
537 /* copied from lov/lov_ea.c, just for debugging, will be removed later */
538 void mdt_dump_lmm(int level, const struct lov_mds_md *lmm)
539 {
540         const struct lov_ost_data_v1 *lod;
541         int i;
542         __s16 stripe_count =
543                 le16_to_cpu(((struct lov_user_md*)lmm)->lmm_stripe_count);
544
545         CDEBUG(level, "objid "LPX64", magic 0x%08X, pattern %#X\n",
546                le64_to_cpu(lmm->lmm_object_id), le32_to_cpu(lmm->lmm_magic),
547                le32_to_cpu(lmm->lmm_pattern));
548         CDEBUG(level,"stripe_size=0x%x, stripe_count=0x%x\n",
549                le32_to_cpu(lmm->lmm_stripe_size),
550                le32_to_cpu(lmm->lmm_stripe_count));
551         LASSERT(stripe_count <= (__s16)LOV_MAX_STRIPE_COUNT);
552         for (i = 0, lod = lmm->lmm_objects; i < stripe_count; i++, lod++) {
553                 CDEBUG(level, "stripe %u idx %u subobj "LPX64"/"LPX64"\n",
554                        i, le32_to_cpu(lod->l_ost_idx),
555                        le64_to_cpu(lod->l_object_gr),
556                        le64_to_cpu(lod->l_object_id));
557         }
558 }
559
560 void mdt_shrink_reply(struct mdt_thread_info *info)
561 {
562         struct req_capsule    *pill = &info->mti_pill;
563         struct mdt_body       *body;
564         int acl_size, md_size, adjust = 0;
565         ENTRY;
566
567         body = req_capsule_server_get(pill, &RMF_MDT_BODY);
568         LASSERT(body != NULL);
569
570         if (body->valid & (OBD_MD_FLDIREA | OBD_MD_FLEASIZE | OBD_MD_LINKNAME))
571                 md_size = body->eadatasize;
572         else
573                 md_size = 0;
574
575         acl_size = body->aclsize;
576
577         CDEBUG(D_INFO, "Shrink to md_size = %d cookie/acl_size = %d" 
578                         " MDSCAPA = %d, OSSCAPA = %d\n",
579                         md_size, acl_size,
580                         (int)(body->valid & OBD_MD_FLMDSCAPA),
581                         (int)(body->valid & OBD_MD_FLOSSCAPA));
582 /*
583             &RMF_MDT_BODY,
584             &RMF_MDT_MD,
585             &RMF_ACL, or &RMF_LOGCOOKIES
586 (optional)  &RMF_CAPA1,
587 (optional)  &RMF_CAPA2,
588 (optional)  something else
589 */
590         adjust += req_capsule_shrink(pill, &RMF_MDT_MD,
591                                     md_size, adjust, 1);
592
593         if (req_capsule_has_field(pill, &RMF_ACL, RCL_SERVER))
594                 adjust += req_capsule_shrink(pill, &RMF_ACL,
595                                             acl_size, adjust, 1);
596         else if (req_capsule_has_field(pill, &RMF_LOGCOOKIES, RCL_SERVER))
597                 adjust += req_capsule_shrink(pill, &RMF_LOGCOOKIES,
598                                             acl_size, adjust, 1);
599
600         if ((req_capsule_has_field(pill, &RMF_CAPA1, RCL_SERVER) &&
601                !(body->valid & OBD_MD_FLMDSCAPA)))
602                 adjust += req_capsule_shrink(pill, &RMF_CAPA1, 0, adjust, 1);
603
604         if ((req_capsule_has_field(pill, &RMF_CAPA2, RCL_SERVER) &&
605                 !(body->valid & OBD_MD_FLOSSCAPA)))
606                 adjust += req_capsule_shrink(pill, &RMF_CAPA2, 0, adjust, 0);
607
608         /*
609          * Some more field should be shrinked if needed.
610          * This should be done by those who added fields to reply message.
611          */
612         EXIT;
613 }
614
615
616 /* if object is dying, pack the lov/llog data,
617  * parameter info->mti_attr should be valid at this point! */
618 int mdt_handle_last_unlink(struct mdt_thread_info *info, struct mdt_object *mo,
619                            const struct md_attr *ma)
620 {
621         struct mdt_body       *repbody;
622         const struct lu_attr *la = &ma->ma_attr;
623         ENTRY;
624
625         repbody = req_capsule_server_get(&info->mti_pill, &RMF_MDT_BODY);
626         LASSERT(repbody != NULL);
627
628         if (ma->ma_valid & MA_INODE)
629                 mdt_pack_attr2body(info, repbody, la, mdt_object_fid(mo));
630
631         if (ma->ma_valid & MA_LOV) {
632                 __u32 mode;
633
634                 if (mdt_object_exists(mo) < 0)
635                         /* If it is a remote object, and we do not retrieve
636                          * EA back unlink reg file*/
637                         mode = S_IFREG;
638                 else
639                         mode = lu_object_attr(&mo->mot_obj.mo_lu);
640
641                 LASSERT(ma->ma_lmm_size);
642                 mdt_dump_lmm(D_INFO, ma->ma_lmm);
643                 repbody->eadatasize = ma->ma_lmm_size;
644                 if (S_ISREG(mode))
645                         repbody->valid |= OBD_MD_FLEASIZE;
646                 else if (S_ISDIR(mode))
647                         repbody->valid |= OBD_MD_FLDIREA;
648                 else
649                         LBUG();
650         }
651
652         if (ma->ma_cookie_size && (ma->ma_valid & MA_COOKIE)) {
653                 repbody->aclsize = ma->ma_cookie_size;
654                 repbody->valid |= OBD_MD_FLCOOKIE;
655         }
656
657         RETURN(0);
658 }
659
660 static __u64 mdt_attr_valid_xlate(__u64 in, struct mdt_reint_record *rr,
661                                   struct md_attr *ma)
662 {
663         __u64 out;
664
665         out = 0;
666         if (in & ATTR_MODE)
667                 out |= LA_MODE;
668         if (in & ATTR_UID)
669                 out |= LA_UID;
670         if (in & ATTR_GID)
671                 out |= LA_GID;
672         if (in & ATTR_SIZE)
673                 out |= LA_SIZE;
674         if (in & ATTR_BLOCKS)
675                 out |= LA_BLOCKS;
676
677         if (in & ATTR_FROM_OPEN)
678                 rr->rr_flags |= MRF_SETATTR_LOCKED;
679
680         if (in & ATTR_ATIME_SET)
681                 out |= LA_ATIME;
682
683         if (in & ATTR_CTIME_SET)
684                 out |= LA_CTIME;
685
686         if (in & ATTR_MTIME_SET)
687                 out |= LA_MTIME;
688
689         if (in & ATTR_ATTR_FLAG)
690                 out |= LA_FLAGS;
691
692         if (in & MDS_OPEN_OWNEROVERRIDE)
693                 out |= MDS_OPEN_OWNEROVERRIDE;
694
695         /*XXX need ATTR_RAW?*/
696         in &= ~(ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_BLOCKS|
697                 ATTR_ATIME|ATTR_MTIME|ATTR_CTIME|ATTR_FROM_OPEN|
698                 ATTR_ATIME_SET|ATTR_CTIME_SET|ATTR_MTIME_SET|
699                 ATTR_ATTR_FLAG|ATTR_RAW|MDS_OPEN_OWNEROVERRIDE);
700         if (in != 0)
701                 CERROR("Unknown attr bits: %#llx\n", in);
702         return out;
703 }
704 /* unpacking */
705
706 static int mdt_setattr_unpack_rec(struct mdt_thread_info *info)
707 {
708         struct md_ucred         *uc  = mdt_ucred(info);
709         struct md_attr          *ma = &info->mti_attr;
710         struct lu_attr          *la = &ma->ma_attr;
711         struct req_capsule      *pill = &info->mti_pill;
712         struct mdt_reint_record *rr = &info->mti_rr;
713         struct mdt_rec_setattr  *rec;
714         ENTRY;
715
716         rec = req_capsule_client_get(pill, &RMF_REC_SETATTR);
717         if (rec == NULL)
718                 RETURN(-EFAULT);
719
720         uc->mu_fsuid = rec->sa_fsuid;
721         uc->mu_fsgid = rec->sa_fsgid;
722         uc->mu_cap   = rec->sa_cap;
723         uc->mu_suppgids[0] = rec->sa_suppgid;
724         uc->mu_suppgids[1] = -1;
725
726         rr->rr_fid1 = &rec->sa_fid;
727         la->la_valid = mdt_attr_valid_xlate(rec->sa_valid, rr, ma);
728         la->la_mode  = rec->sa_mode;
729         la->la_flags = rec->sa_attr_flags;
730         la->la_uid   = rec->sa_uid;
731         la->la_gid   = rec->sa_gid;
732         la->la_size  = rec->sa_size;
733         la->la_blocks = rec->sa_blocks;
734         la->la_ctime = rec->sa_ctime;
735         la->la_atime = rec->sa_atime;
736         la->la_mtime = rec->sa_mtime;
737         ma->ma_valid = MA_INODE;
738
739         if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT))
740                 mdt_set_capainfo(info, 0, rr->rr_fid1,
741                                  req_capsule_client_get(pill, &RMF_CAPA1));
742
743         RETURN(0);
744 }
745
746 static int mdt_epoch_unpack(struct mdt_thread_info *info)
747 {
748         struct req_capsule *pill = &info->mti_pill;
749         ENTRY;
750
751         if (req_capsule_get_size(pill, &RMF_MDT_EPOCH, RCL_CLIENT))
752                 info->mti_epoch = req_capsule_client_get(pill, &RMF_MDT_EPOCH);
753         else
754                 info->mti_epoch = NULL;
755         RETURN(info->mti_epoch == NULL ? -EFAULT : 0);
756 }
757
758 static int mdt_setattr_unpack(struct mdt_thread_info *info)
759 {
760         struct md_attr          *ma = &info->mti_attr;
761         struct req_capsule      *pill = &info->mti_pill;
762         int rc;
763         ENTRY;
764
765         rc = mdt_setattr_unpack_rec(info);
766         if (rc)
767                 RETURN(rc);
768
769         /* Epoch may be absent */
770         mdt_epoch_unpack(info);
771
772         if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) {
773                 ma->ma_lmm = req_capsule_client_get(pill, &RMF_EADATA);
774                 ma->ma_lmm_size = req_capsule_get_size(pill, &RMF_EADATA,
775                                                        RCL_CLIENT);
776                 ma->ma_valid |= MA_LOV;
777         }
778
779         if (req_capsule_field_present(pill, &RMF_LOGCOOKIES, RCL_CLIENT)) {
780                 ma->ma_cookie = req_capsule_client_get(pill,
781                                                        &RMF_LOGCOOKIES);
782                 ma->ma_cookie_size = req_capsule_get_size(pill,
783                                                           &RMF_LOGCOOKIES,
784                                                           RCL_CLIENT);
785                 ma->ma_valid |= MA_COOKIE;
786         }
787
788         RETURN(0);
789 }
790
791 int mdt_close_unpack(struct mdt_thread_info *info)
792 {
793         int rc;
794         ENTRY;
795
796         rc = mdt_epoch_unpack(info);
797         if (rc)
798                 RETURN(rc);
799
800         RETURN(mdt_setattr_unpack_rec(info));
801 }
802
803 static int mdt_create_unpack(struct mdt_thread_info *info)
804 {
805         struct md_ucred         *uc  = mdt_ucred(info);
806         struct mdt_rec_create   *rec;
807         struct lu_attr          *attr = &info->mti_attr.ma_attr;
808         struct mdt_reint_record *rr = &info->mti_rr;
809         struct req_capsule      *pill = &info->mti_pill;
810         struct md_op_spec       *sp = &info->mti_spec;
811         ENTRY;
812
813         rec = req_capsule_client_get(pill, &RMF_REC_CREATE);
814         if (rec == NULL)
815                 RETURN(-EFAULT);
816
817         uc->mu_fsuid = rec->cr_fsuid;
818         uc->mu_fsgid = rec->cr_fsgid;
819         uc->mu_cap   = rec->cr_cap;
820         uc->mu_suppgids[0] = rec->cr_suppgid1;
821         uc->mu_suppgids[1] = -1;
822
823         rr->rr_fid1 = &rec->cr_fid1;
824         rr->rr_fid2 = &rec->cr_fid2;
825         attr->la_mode = rec->cr_mode;
826         attr->la_rdev  = rec->cr_rdev;
827         attr->la_uid   = rec->cr_fsuid;
828         attr->la_gid   = rec->cr_fsgid;
829         attr->la_ctime = rec->cr_time;
830         attr->la_mtime = rec->cr_time;
831         attr->la_atime = rec->cr_time;
832         attr->la_valid = LA_MODE | LA_RDEV | LA_UID | LA_GID |
833                          LA_CTIME | LA_MTIME | LA_ATIME;
834         memset(&sp->u, 0, sizeof(sp->u));
835         sp->sp_cr_flags = rec->cr_flags;
836         sp->sp_ck_split = !!(rec->cr_bias & MDS_CHECK_SPLIT);
837         info->mti_cross_ref = !!(rec->cr_bias & MDS_CROSS_REF);
838
839         if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT))
840                 mdt_set_capainfo(info, 0, rr->rr_fid1,
841                                  req_capsule_client_get(pill, &RMF_CAPA1));
842         mdt_set_capainfo(info, 1, rr->rr_fid2, BYPASS_CAPA);
843
844         rr->rr_name = req_capsule_client_get(pill, &RMF_NAME);
845         rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1;
846         LASSERT(rr->rr_namelen > 0);
847         
848 #ifdef CONFIG_FS_POSIX_ACL
849         if (sp->sp_cr_flags & MDS_CREATE_RMT_ACL) {
850                 if (S_ISDIR(attr->la_mode))
851                         sp->u.sp_pfid = rr->rr_fid1;
852                 req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_RMT_ACL);
853                 LASSERT(req_capsule_field_present(pill, &RMF_EADATA,
854                                                   RCL_CLIENT));
855                 sp->u.sp_ea.eadata = req_capsule_client_get(pill, &RMF_EADATA);
856                 sp->u.sp_ea.eadatalen = req_capsule_get_size(pill, &RMF_EADATA,
857                                                                 RCL_CLIENT);
858                 sp->u.sp_ea.fid = rr->rr_fid1;
859                 RETURN(0);
860         }
861 #endif
862         if (S_ISDIR(attr->la_mode)) {
863                 /* pass parent fid for cross-ref cases */
864                 sp->u.sp_pfid = rr->rr_fid1;
865                 if (sp->sp_cr_flags & MDS_CREATE_SLAVE_OBJ) {
866                         /* create salve object req, need
867                          * unpack split ea here
868                          */
869                        req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_SLAVE);
870                        LASSERT(req_capsule_field_present(pill, &RMF_EADATA,
871                                                          RCL_CLIENT));
872                        sp->u.sp_ea.eadata = req_capsule_client_get(pill,
873                                                                    &RMF_EADATA);
874                        sp->u.sp_ea.eadatalen = req_capsule_get_size(pill,
875                                                                     &RMF_EADATA,
876                                                                     RCL_CLIENT);
877                        sp->u.sp_ea.fid = rr->rr_fid1;
878                 }
879         } else if (S_ISLNK(attr->la_mode)) {
880                 const char *tgt = NULL;
881
882                 req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_SYM);
883                 if (req_capsule_field_present(pill, &RMF_SYMTGT, RCL_CLIENT)) {
884                         tgt = req_capsule_client_get(pill, &RMF_SYMTGT);
885                         sp->u.sp_symname = tgt;
886                 }
887                 if (tgt == NULL)
888                         RETURN(-EFAULT);
889         }
890         RETURN(0);
891 }
892
893 static int mdt_link_unpack(struct mdt_thread_info *info)
894 {
895         struct md_ucred         *uc  = mdt_ucred(info);
896         struct mdt_rec_link     *rec;
897         struct lu_attr          *attr = &info->mti_attr.ma_attr;
898         struct mdt_reint_record *rr = &info->mti_rr;
899         struct req_capsule      *pill = &info->mti_pill;
900         ENTRY;
901
902         rec = req_capsule_client_get(pill, &RMF_REC_LINK);
903         if (rec == NULL)
904                 RETURN(-EFAULT);
905
906         uc->mu_fsuid = rec->lk_fsuid;
907         uc->mu_fsgid = rec->lk_fsgid;
908         uc->mu_cap   = rec->lk_cap;
909         uc->mu_suppgids[0] = rec->lk_suppgid1;
910         uc->mu_suppgids[1] = rec->lk_suppgid2;
911
912         attr->la_uid = rec->lk_fsuid;
913         attr->la_gid = rec->lk_fsgid;
914         rr->rr_fid1 = &rec->lk_fid1;
915         rr->rr_fid2 = &rec->lk_fid2;
916         attr->la_ctime = rec->lk_time;
917         attr->la_mtime = rec->lk_time;
918         attr->la_valid = LA_UID | LA_GID | LA_CTIME | LA_MTIME;
919
920         if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT))
921                 mdt_set_capainfo(info, 0, rr->rr_fid1,
922                                  req_capsule_client_get(pill, &RMF_CAPA1));
923         if (req_capsule_get_size(pill, &RMF_CAPA2, RCL_CLIENT))
924                 mdt_set_capainfo(info, 1, rr->rr_fid2,
925                                  req_capsule_client_get(pill, &RMF_CAPA2));
926
927         rr->rr_name = req_capsule_client_get(pill, &RMF_NAME);
928         if (rr->rr_name == NULL)
929                 RETURN(-EFAULT);
930         rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1;
931         LASSERT(rr->rr_namelen > 0);
932         info->mti_spec.sp_ck_split = !!(rec->lk_bias & MDS_CHECK_SPLIT);
933         info->mti_cross_ref = !!(rec->lk_bias & MDS_CROSS_REF);
934
935         RETURN(0);
936 }
937
938 static int mdt_unlink_unpack(struct mdt_thread_info *info)
939 {
940         struct md_ucred         *uc  = mdt_ucred(info);
941         struct mdt_rec_unlink   *rec;
942         struct md_attr          *ma = &info->mti_attr;
943         struct lu_attr          *attr = &info->mti_attr.ma_attr;
944         struct mdt_reint_record *rr = &info->mti_rr;
945         struct req_capsule      *pill = &info->mti_pill;
946         ENTRY;
947
948         rec = req_capsule_client_get(pill, &RMF_REC_UNLINK);
949         if (rec == NULL)
950                 RETURN(-EFAULT);
951
952         uc->mu_fsuid = rec->ul_fsuid;
953         uc->mu_fsgid = rec->ul_fsgid;
954         uc->mu_cap   = rec->ul_cap;
955         uc->mu_suppgids[0] = rec->ul_suppgid;
956         uc->mu_suppgids[1] = -1;
957
958         attr->la_uid = rec->ul_fsuid;
959         attr->la_gid = rec->ul_fsgid;
960         rr->rr_fid1 = &rec->ul_fid1;
961         rr->rr_fid2 = &rec->ul_fid2;
962         attr->la_ctime = rec->ul_time;
963         attr->la_mtime = rec->ul_time;
964         attr->la_mode  = rec->ul_mode;
965         attr->la_valid = LA_UID | LA_GID | LA_CTIME | LA_MTIME | LA_MODE;
966
967         if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT))
968                 mdt_set_capainfo(info, 0, rr->rr_fid1,
969                                  req_capsule_client_get(pill, &RMF_CAPA1));
970
971         rr->rr_name = req_capsule_client_get(pill, &RMF_NAME);
972         if (rr->rr_name == NULL)
973                 RETURN(-EFAULT);
974         rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1;
975         LASSERT(rr->rr_namelen > 0);
976         info->mti_spec.sp_ck_split = !!(rec->ul_bias & MDS_CHECK_SPLIT);
977         info->mti_cross_ref = !!(rec->ul_bias & MDS_CROSS_REF);
978         if (rec->ul_bias & MDS_VTX_BYPASS)
979                 ma->ma_attr_flags |= MDS_VTX_BYPASS;
980         else
981                 ma->ma_attr_flags &= ~MDS_VTX_BYPASS;
982
983         RETURN(0);
984 }
985
986 static int mdt_rename_unpack(struct mdt_thread_info *info)
987 {
988         struct md_ucred         *uc = mdt_ucred(info);
989         struct mdt_rec_rename   *rec;
990         struct md_attr          *ma = &info->mti_attr;
991         struct lu_attr          *attr = &info->mti_attr.ma_attr;
992         struct mdt_reint_record *rr = &info->mti_rr;
993         struct req_capsule      *pill = &info->mti_pill;
994         ENTRY;
995
996         rec = req_capsule_client_get(pill, &RMF_REC_RENAME);
997         if (rec == NULL)
998                 RETURN(-EFAULT);
999
1000         uc->mu_fsuid = rec->rn_fsuid;
1001         uc->mu_fsgid = rec->rn_fsgid;
1002         uc->mu_cap   = rec->rn_cap;
1003         uc->mu_suppgids[0] = rec->rn_suppgid1;
1004         uc->mu_suppgids[1] = rec->rn_suppgid2;
1005
1006         attr->la_uid = rec->rn_fsuid;
1007         attr->la_gid = rec->rn_fsgid;
1008         rr->rr_fid1 = &rec->rn_fid1;
1009         rr->rr_fid2 = &rec->rn_fid2;
1010         attr->la_ctime = rec->rn_time;
1011         attr->la_mtime = rec->rn_time;
1012         /* rename_tgt contains the mode already */
1013         attr->la_mode = rec->rn_mode;
1014         attr->la_valid = LA_UID | LA_GID | LA_CTIME | LA_MTIME | LA_MODE;
1015
1016         if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT))
1017                 mdt_set_capainfo(info, 0, rr->rr_fid1,
1018                                  req_capsule_client_get(pill, &RMF_CAPA1));
1019         if (req_capsule_get_size(pill, &RMF_CAPA2, RCL_CLIENT))
1020                 mdt_set_capainfo(info, 1, rr->rr_fid2,
1021                                  req_capsule_client_get(pill, &RMF_CAPA2));
1022
1023         rr->rr_name = req_capsule_client_get(pill, &RMF_NAME);
1024         rr->rr_tgt = req_capsule_client_get(pill, &RMF_SYMTGT);
1025         if (rr->rr_name == NULL || rr->rr_tgt == NULL)
1026                 RETURN(-EFAULT);
1027         rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1;
1028         LASSERT(rr->rr_namelen > 0);
1029         rr->rr_tgtlen = req_capsule_get_size(pill, &RMF_SYMTGT, RCL_CLIENT) - 1;
1030         LASSERT(rr->rr_tgtlen > 0);
1031         info->mti_spec.sp_ck_split = !!(rec->rn_bias & MDS_CHECK_SPLIT);
1032         info->mti_cross_ref = !!(rec->rn_bias & MDS_CROSS_REF);
1033         if (rec->rn_bias & MDS_VTX_BYPASS)
1034                 ma->ma_attr_flags |= MDS_VTX_BYPASS;
1035         else
1036                 ma->ma_attr_flags &= ~MDS_VTX_BYPASS;
1037
1038         RETURN(0);
1039 }
1040
1041 static int mdt_open_unpack(struct mdt_thread_info *info)
1042 {
1043         struct md_ucred         *uc = mdt_ucred(info);
1044         struct mdt_rec_create   *rec;
1045         struct lu_attr          *attr = &info->mti_attr.ma_attr;
1046         struct req_capsule      *pill = &info->mti_pill;
1047         struct mdt_reint_record *rr   = &info->mti_rr;
1048         struct ptlrpc_request   *req  = mdt_info_req(info);
1049         ENTRY;
1050
1051         rec = req_capsule_client_get(pill, &RMF_REC_CREATE);
1052         if (rec == NULL)
1053                 RETURN(-EFAULT);
1054
1055         uc->mu_fsuid = rec->cr_fsuid;
1056         uc->mu_fsgid = rec->cr_fsgid;
1057         uc->mu_cap   = rec->cr_cap;
1058         uc->mu_suppgids[0] = rec->cr_suppgid1;
1059         uc->mu_suppgids[1] = rec->cr_suppgid2;
1060
1061         rr->rr_fid1   = &rec->cr_fid1;
1062         rr->rr_fid2   = &rec->cr_fid2;
1063         rr->rr_handle = &rec->cr_old_handle;
1064         attr->la_mode = rec->cr_mode;
1065         attr->la_rdev  = rec->cr_rdev;
1066         attr->la_uid   = rec->cr_fsuid;
1067         attr->la_gid   = rec->cr_fsgid;
1068         attr->la_ctime = rec->cr_time;
1069         attr->la_mtime = rec->cr_time;
1070         attr->la_atime = rec->cr_time;
1071         attr->la_valid = LA_MODE  | LA_RDEV  | LA_UID   | LA_GID |
1072                          LA_CTIME | LA_MTIME | LA_ATIME;
1073         memset(&info->mti_spec.u, 0, sizeof(info->mti_spec.u));
1074         info->mti_spec.sp_cr_flags = rec->cr_flags;
1075         info->mti_replayepoch = rec->cr_ioepoch;
1076
1077         info->mti_spec.sp_ck_split = !!(rec->cr_bias & MDS_CHECK_SPLIT);
1078         info->mti_cross_ref = !!(rec->cr_bias & MDS_CROSS_REF);
1079
1080         if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT))
1081                 mdt_set_capainfo(info, 0, rr->rr_fid1,
1082                                  req_capsule_client_get(pill, &RMF_CAPA1));
1083         if ((lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY) &&
1084             (req_capsule_get_size(pill, &RMF_CAPA2, RCL_CLIENT))) {
1085 #if 0
1086                 mdt_set_capainfo(info, 1, rr->rr_fid2,
1087                                  req_capsule_client_get(pill, &RMF_CAPA2));
1088 #else
1089                 /*
1090                  * FIXME: capa in replay open request might have expired,
1091                  * bypass capa check. Security hole?
1092                  */
1093                 mdt_set_capainfo(info, 0, rr->rr_fid1, BYPASS_CAPA);
1094                 mdt_set_capainfo(info, 1, rr->rr_fid2, BYPASS_CAPA);
1095 #endif
1096         }
1097
1098         rr->rr_name = req_capsule_client_get(pill, &RMF_NAME);
1099         if (rr->rr_name == NULL)
1100                 RETURN(-EFAULT);
1101         rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1;
1102         LASSERT(rr->rr_namelen > 0);
1103
1104         if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) {
1105                 struct md_op_spec *sp = &info->mti_spec;
1106                 sp->u.sp_ea.eadata = req_capsule_client_get(pill,
1107                                                             &RMF_EADATA);
1108                 sp->u.sp_ea.eadatalen = req_capsule_get_size(pill,
1109                                                              &RMF_EADATA,
1110                                                              RCL_CLIENT);
1111                 if (lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY)
1112                         sp->u.sp_ea.no_lov_create = 1;
1113         }
1114
1115         RETURN(0);
1116 }
1117
1118 typedef int (*reint_unpacker)(struct mdt_thread_info *info);
1119
1120 static reint_unpacker mdt_reint_unpackers[REINT_MAX] = {
1121         [REINT_SETATTR]  = mdt_setattr_unpack,
1122         [REINT_CREATE]   = mdt_create_unpack,
1123         [REINT_LINK]     = mdt_link_unpack,
1124         [REINT_UNLINK]   = mdt_unlink_unpack,
1125         [REINT_RENAME]   = mdt_rename_unpack,
1126         [REINT_OPEN]     = mdt_open_unpack
1127 };
1128
1129 int mdt_reint_unpack(struct mdt_thread_info *info, __u32 op)
1130 {
1131         int rc;
1132         ENTRY;
1133
1134         memset(&info->mti_rr, 0, sizeof(info->mti_rr));
1135         if (op < REINT_MAX && mdt_reint_unpackers[op] != NULL) {
1136                 info->mti_rr.rr_opcode = op;
1137                 rc = mdt_reint_unpackers[op](info);
1138         } else {
1139                 CERROR("Unexpected opcode %d\n", op);
1140                 rc = -EFAULT;
1141         }
1142         RETURN(rc);
1143 }