Whamcloud - gitweb
LU-1303 lod: introduce lod device
[fs/lustre-release.git] / lustre / mdt / mdt_lib.c
index c8da922..b734013 100644 (file)
@@ -1,6 +1,4 @@
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
+/*
  * GPL HEADER START
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -28,6 +26,8 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright (c) 2011, 2012, Whamcloud, Inc.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
  * Author: Fan Yong <fanyong@clusterfs.com>
  */
 
-
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
 #define DEBUG_SUBSYSTEM S_MDS
 
 #include "mdt_internal.h"
@@ -548,12 +544,14 @@ void mdt_dump_lmm(int level, const struct lov_mds_md *lmm)
                        le64_to_cpu(lod->l_object_id));
 }
 
-void mdt_shrink_reply(struct mdt_thread_info *info)
+/* Shrink and/or grow reply buffers */
+int mdt_fix_reply(struct mdt_thread_info *info)
 {
         struct req_capsule *pill = info->mti_pill;
         struct mdt_body    *body;
-        int                md_size;
+        int                md_size, md_packed = 0;
         int                acl_size;
+        int                rc = 0;
         ENTRY;
 
         body = req_capsule_server_get(pill, &RMF_MDT_BODY);
@@ -586,9 +584,24 @@ void mdt_shrink_reply(struct mdt_thread_info *info)
 (optional)  something else
 */
 
-        if (req_capsule_has_field(pill, &RMF_MDT_MD, RCL_SERVER))
-                req_capsule_shrink(pill, &RMF_MDT_MD, md_size,
-                                   RCL_SERVER);
+        /* MDT_MD buffer may be bigger than packed value, let's shrink all
+         * buffers before growing it */
+       if (info->mti_big_lmm_used) {
+                LASSERT(req_capsule_has_field(pill, &RMF_MDT_MD, RCL_SERVER));
+                md_packed = req_capsule_get_size(pill, &RMF_MDT_MD,
+                                                 RCL_SERVER);
+                LASSERT(md_packed > 0);
+                /* buffer must be allocated separately */
+                LASSERT(info->mti_attr.ma_lmm !=
+                        req_capsule_server_get(pill, &RMF_MDT_MD));
+                req_capsule_shrink(pill, &RMF_MDT_MD, 0, RCL_SERVER);
+                /* free big lmm if md_size is not needed */
+                if (md_size == 0)
+                       info->mti_big_lmm_used = 0;
+        } else if (req_capsule_has_field(pill, &RMF_MDT_MD, RCL_SERVER)) {
+                req_capsule_shrink(pill, &RMF_MDT_MD, md_size, RCL_SERVER);
+        }
+
         if (req_capsule_has_field(pill, &RMF_ACL, RCL_SERVER))
                 req_capsule_shrink(pill, &RMF_ACL, acl_size, RCL_SERVER);
         else if (req_capsule_has_field(pill, &RMF_LOGCOOKIES, RCL_SERVER))
@@ -607,7 +620,38 @@ void mdt_shrink_reply(struct mdt_thread_info *info)
          * Some more field should be shrinked if needed.
          * This should be done by those who added fields to reply message.
          */
-        EXIT;
+
+        /* Grow MD buffer if needed finally */
+       if (info->mti_big_lmm_used) {
+                void *lmm;
+
+                LASSERT(md_size > md_packed);
+                CDEBUG(D_INFO, "Enlarge reply buffer, need extra %d bytes\n",
+                       md_size - md_packed);
+                rc = req_capsule_server_grow(pill, &RMF_MDT_MD, md_size);
+                if (rc) {
+                        /* we can't answer with proper LOV EA, drop flags,
+                         * the rc is also returned so this request is
+                         * considered as failed */
+                        body->valid &= ~(OBD_MD_FLDIREA | OBD_MD_FLEASIZE);
+                        /* don't return transno along with error */
+                        lustre_msg_set_transno(pill->rc_req->rq_repmsg, 0);
+                } else {
+                        /* now we need to pack right LOV EA */
+                        lmm = req_capsule_server_get(pill, &RMF_MDT_MD);
+                        LASSERT(req_capsule_get_size(pill, &RMF_MDT_MD,
+                                                     RCL_SERVER) ==
+                                info->mti_attr.ma_lmm_size);
+                        memcpy(lmm, info->mti_attr.ma_lmm,
+                               info->mti_attr.ma_lmm_size);
+                }
+                /* update mdt_max_mdsize so clients will be aware about that */
+                if (info->mti_mdt->mdt_max_mdsize < info->mti_attr.ma_lmm_size)
+                        info->mti_mdt->mdt_max_mdsize =
+                                                    info->mti_attr.ma_lmm_size;
+               info->mti_big_lmm_used = 0;
+        }
+        RETURN(rc);
 }
 
 
@@ -835,6 +879,7 @@ static inline int mdt_dlmreq_unpack(struct mdt_thread_info *info) {
 
 static int mdt_setattr_unpack(struct mdt_thread_info *info)
 {
+        struct mdt_reint_record *rr = &info->mti_rr;
         struct md_attr          *ma = &info->mti_attr;
         struct req_capsule      *pill = info->mti_pill;
         int rc;
@@ -847,10 +892,15 @@ static int mdt_setattr_unpack(struct mdt_thread_info *info)
         /* Epoch may be absent */
         mdt_ioepoch_unpack(info);
 
-        ma->ma_lmm_size = req_capsule_get_size(pill, &RMF_EADATA, RCL_CLIENT);
-        if (ma->ma_lmm_size) {
-                ma->ma_lmm = req_capsule_client_get(pill, &RMF_EADATA);
-                ma->ma_valid |= MA_LOV;
+        if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) {
+                rr->rr_eadata = req_capsule_client_get(pill, &RMF_EADATA);
+                rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA,
+                                                        RCL_CLIENT);
+                ma->ma_lmm_size = rr->rr_eadatalen;
+                if (ma->ma_lmm_size > 0) {
+                        ma->ma_lmm = (void *)rr->rr_eadata;
+                        ma->ma_valid |= MA_LOV;
+                }
         }
 
         ma->ma_cookie_size = req_capsule_get_size(pill, &RMF_LOGCOOKIES,
@@ -936,9 +986,11 @@ static int mdt_create_unpack(struct mdt_thread_info *info)
                 req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_RMT_ACL);
                 LASSERT(req_capsule_field_present(pill, &RMF_EADATA,
                                                   RCL_CLIENT));
-                sp->u.sp_ea.eadata = req_capsule_client_get(pill, &RMF_EADATA);
-                sp->u.sp_ea.eadatalen = req_capsule_get_size(pill, &RMF_EADATA,
-                                                             RCL_CLIENT);
+                rr->rr_eadata = req_capsule_client_get(pill, &RMF_EADATA);
+                rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA,
+                                                        RCL_CLIENT);
+                sp->u.sp_ea.eadata = rr->rr_eadata;
+                sp->u.sp_ea.eadatalen = rr->rr_eadatalen;
                 sp->u.sp_ea.fid = rr->rr_fid1;
                 RETURN(0);
         }
@@ -953,11 +1005,13 @@ static int mdt_create_unpack(struct mdt_thread_info *info)
                        req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_SLAVE);
                        LASSERT(req_capsule_field_present(pill, &RMF_EADATA,
                                                          RCL_CLIENT));
-                       sp->u.sp_ea.eadata = req_capsule_client_get(pill,
-                                                                   &RMF_EADATA);
-                       sp->u.sp_ea.eadatalen = req_capsule_get_size(pill,
-                                                                    &RMF_EADATA,
-                                                                    RCL_CLIENT);
+                       rr->rr_eadata = req_capsule_client_get(pill,
+                                                              &RMF_EADATA);
+                       rr->rr_eadatalen = req_capsule_get_size(pill,
+                                                               &RMF_EADATA,
+                                                               RCL_CLIENT);
+                       sp->u.sp_ea.eadata = rr->rr_eadata;
+                       sp->u.sp_ea.eadatalen = rr->rr_eadatalen;
                        sp->u.sp_ea.fid = rr->rr_fid1;
                        RETURN(0);
                 }
@@ -1080,6 +1134,8 @@ static int mdt_unlink_unpack(struct mdt_thread_info *info)
                 ma->ma_attr_flags &= ~MDS_VTX_BYPASS;
 
         info->mti_spec.no_create = !!req_is_replay(mdt_info_req(info));
+        /* last unlink need LOV EA sent back */
+        rr->rr_eadatalen = info->mti_mdt->mdt_max_mdsize;
 
         rc = mdt_dlmreq_unpack(info);
         RETURN(rc);
@@ -1140,6 +1196,8 @@ static int mdt_rename_unpack(struct mdt_thread_info *info)
                 ma->ma_attr_flags &= ~MDS_VTX_BYPASS;
 
         info->mti_spec.no_create = !!req_is_replay(mdt_info_req(info));
+        /* rename may contain unlink so we might need LOV EA sent back */
+        rr->rr_eadatalen = info->mti_mdt->mdt_max_mdsize;
 
         rc = mdt_dlmreq_unpack(info);
         RETURN(rc);
@@ -1212,12 +1270,26 @@ static int mdt_open_unpack(struct mdt_thread_info *info)
                 RETURN(-EFAULT);
         rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1;
 
-        sp->u.sp_ea.eadatalen = req_capsule_get_size(pill, &RMF_EADATA,
-                                                     RCL_CLIENT);
-        if (sp->u.sp_ea.eadatalen) {
-                sp->u.sp_ea.eadata = req_capsule_client_get(pill, &RMF_EADATA);
-                sp->no_create = !!req_is_replay(req);
-        }
+        if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) {
+                rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA,
+                                                        RCL_CLIENT);
+                if (rr->rr_eadatalen > 0) {
+                        rr->rr_eadata = req_capsule_client_get(pill,
+                                                               &RMF_EADATA);
+                        sp->u.sp_ea.eadatalen = rr->rr_eadatalen;
+                        sp->u.sp_ea.eadata = rr->rr_eadata;
+                        sp->no_create = !!req_is_replay(req);
+                }
+
+                /*
+                 * Client default md_size may be 0 right after client start,
+                 * until all osc are connected, set here just some reasonable
+                 * value to prevent misbehavior.
+                 */
+                if (rr->rr_eadatalen == 0 &&
+                    !(info->mti_spec.sp_cr_flags & MDS_OPEN_DELAY_CREATE))
+                       rr->rr_eadatalen = MIN_MD_SIZE;
+       }
 
         RETURN(0);
 }
@@ -1264,11 +1336,20 @@ static int mdt_setxattr_unpack(struct mdt_thread_info *info)
         rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1;
         LASSERT(rr->rr_namelen > 0);
 
-        rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA, RCL_CLIENT);
-        if (rr->rr_eadatalen > 0) {
-                rr->rr_eadata = req_capsule_client_get(pill, &RMF_EADATA);
-                if (rr->rr_eadata == NULL)
-                        RETURN(-EFAULT);
+        if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) {
+                rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA,
+                                                        RCL_CLIENT);
+                if (rr->rr_eadatalen > 0) {
+                        rr->rr_eadata = req_capsule_client_get(pill,
+                                                               &RMF_EADATA);
+                        if (rr->rr_eadata == NULL)
+                                RETURN(-EFAULT);
+                } else {
+                        rr->rr_eadata = NULL;
+                }
+        } else if (!(attr->la_valid & OBD_MD_FLXATTRRM)) {
+                CDEBUG(D_INFO, "no xattr data supplied\n");
+                RETURN(-EFAULT);
         }
 
         RETURN(0);