nfs-ganesha 1.4

nfs_Mkdir.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  * 
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  * 
00023  * ---------------------------------------
00024  */
00025 
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif
00040 
00041 #ifdef _SOLARIS
00042 #include "solaris_port.h"
00043 #endif
00044 #include <stdio.h>
00045 #include <string.h>
00046 #include <pthread.h>
00047 #include <fcntl.h>
00048 #include <sys/file.h>           /* for having FNDELAY */
00049 #include "HashData.h"
00050 #include "HashTable.h"
00051 #include "log.h"
00052 #include "ganesha_rpc.h"
00053 #include "nfs23.h"
00054 #include "nfs4.h"
00055 #include "mount.h"
00056 #include "nfs_core.h"
00057 #include "cache_inode.h"
00058 #include "nfs_exports.h"
00059 #include "nfs_creds.h"
00060 #include "nfs_proto_functions.h"
00061 #include "nfs_tools.h"
00062 #include "nfs_file_handle.h"
00063 #include "nfs_proto_tools.h"
00064 
00084 int nfs_Mkdir(nfs_arg_t *parg,
00085               exportlist_t *pexport,
00086               fsal_op_context_t *pcontext,
00087               nfs_worker_data_t *pworker,
00088               struct svc_req *preq,
00089               nfs_res_t *pres)
00090 {
00091   char *str_dir_name = NULL;
00092   fsal_accessmode_t mode = 0;
00093   cache_entry_t *dir_pentry = NULL;
00094   cache_entry_t *parent_pentry = NULL;
00095   fsal_attrib_list_t parent_attr;
00096   fsal_attrib_list_t attr;
00097   fsal_attrib_list_t *ppre_attr;
00098   fsal_attrib_list_t attr_parent_after;
00099   cache_inode_file_type_t parent_filetype;
00100   fsal_handle_t *pfsal_handle;
00101   fsal_name_t dir_name;
00102   cache_inode_status_t cache_status = CACHE_INODE_SUCCESS;
00103   cache_inode_status_t cache_status_lookup;
00104   cache_inode_create_arg_t create_arg;
00105   int rc = NFS_REQ_OK;
00106 #ifdef _USE_QUOTA
00107   fsal_status_t fsal_status ;
00108 #endif
00109 
00110   memset(&create_arg, 0, sizeof(create_arg));
00111 
00112   if(isDebug(COMPONENT_NFSPROTO))
00113     {
00114       char str[LEN_FH_STR];
00115 
00116       switch (preq->rq_vers)
00117         {
00118         case NFS_V2:
00119           str_dir_name = parg->arg_mkdir2.where.name;
00120           break;
00121         case NFS_V3:
00122           str_dir_name = parg->arg_mkdir3.where.name;
00123           break;
00124         }
00125 
00126       nfs_FhandleToStr(preq->rq_vers,
00127                        &(parg->arg_mkdir2.where.dir),
00128                        &(parg->arg_mkdir3.where.dir),
00129                        NULL,
00130                        str);
00131       LogDebug(COMPONENT_NFSPROTO,
00132                "REQUEST PROCESSING: Calling nfs_Mkdir handle: %s name: %s",
00133                str, str_dir_name);
00134     }
00135 
00136   if(preq->rq_vers == NFS_V3)
00137     {
00138       /* to avoid setting it on each error case */
00139       pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.before.attributes_follow = FALSE;
00140       pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.after.attributes_follow = FALSE;
00141       ppre_attr = NULL;
00142     }
00143 
00144   if((parent_pentry = nfs_FhandleToCache(preq->rq_vers,
00145                                          &(parg->arg_mkdir2.where.dir),
00146                                          &(parg->arg_mkdir3.where.dir),
00147                                          NULL,
00148                                          &(pres->res_dirop2.status),
00149                                          &(pres->res_mkdir3.status),
00150                                          NULL,
00151                                          &parent_attr,
00152                                          pcontext, &rc)) == NULL)
00153     {
00154       /* Stale NFS FH ? */
00155       goto out;
00156     }
00157 
00158   /* get directory attributes before action (for V3 reply) */
00159   ppre_attr = &parent_attr;
00160 
00161   /* Extract the filetype */
00162   parent_filetype = cache_inode_fsal_type_convert(parent_attr.type);
00163 
00164   /*
00165    * Sanity checks: 
00166    */
00167   if(parent_filetype != DIRECTORY)
00168     {
00169       switch (preq->rq_vers)
00170         {
00171         case NFS_V2:
00172           pres->res_dirop2.status = NFSERR_NOTDIR;
00173           break;
00174 
00175         case NFS_V3:
00176           pres->res_mkdir3.status = NFS3ERR_NOTDIR;
00177           break;
00178         }
00179 
00180       rc = NFS_REQ_OK;
00181       goto out;
00182     }
00183 
00184 
00185 #ifdef _USE_QUOTA
00186     /* if quota support is active, then we should check is the FSAL allows inode creation or not */
00187     fsal_status = FSAL_check_quota( pexport->fullpath, 
00188                                     FSAL_QUOTA_INODES,
00189                                     FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ;
00190     if( FSAL_IS_ERROR( fsal_status ) )
00191      {
00192 
00193        switch (preq->rq_vers)
00194          {
00195            case NFS_V2:
00196              pres->res_dirop2.status = NFSERR_DQUOT;
00197              break;
00198 
00199            case NFS_V3:
00200              pres->res_mkdir3.status = NFS3ERR_DQUOT;
00201              break;
00202          }
00203 
00204        rc = NFS_REQ_OK ;
00205        goto out;
00206      }
00207 #endif /* _USE_QUOTA */
00208 
00209 
00210   switch (preq->rq_vers)
00211     {
00212     case NFS_V2:
00213       str_dir_name = parg->arg_mkdir2.where.name;
00214 
00215       if(parg->arg_mkdir2.attributes.mode != (unsigned int)-1)
00216         {
00217           mode = (fsal_accessmode_t) parg->arg_mkdir2.attributes.mode;
00218         }
00219       else
00220         {
00221           mode = (fsal_accessmode_t) 0;
00222         }
00223       break;
00224 
00225     case NFS_V3:
00226       str_dir_name = parg->arg_mkdir3.where.name;
00227 
00228       if(parg->arg_mkdir3.attributes.mode.set_it == TRUE)
00229         mode = (fsal_accessmode_t) parg->arg_mkdir3.attributes.mode.set_mode3_u.mode;
00230       else
00231         mode = (fsal_accessmode_t) 0;
00232       break;
00233     }
00234 
00235   //if(str_dir_name == NULL || strlen(str_dir_name) == 0)
00236   if(str_dir_name == NULL || *str_dir_name == '\0' )
00237     {
00238       if(preq->rq_vers == NFS_V2)
00239         pres->res_dirop2.status = NFSERR_IO;
00240       if(preq->rq_vers == NFS_V3)
00241         pres->res_mkdir3.status = NFS3ERR_INVAL;
00242     }
00243   else
00244     {
00245       /* Make the directory */
00246       if((cache_status = cache_inode_error_convert(FSAL_str2name(str_dir_name,
00247                                                                  FSAL_MAX_NAME_LEN,
00248                                                                  &dir_name))) ==
00249          CACHE_INODE_SUCCESS)
00250         {
00251           /*
00252            * Lookup file to see if it exists.  If so, use it.  Otherwise
00253            * create a new one.
00254            */
00255           dir_pentry = cache_inode_lookup(parent_pentry,
00256                                           &dir_name,
00257                                           &attr,
00258                                           pcontext,
00259                                           &cache_status_lookup);
00260 
00261           if(cache_status_lookup == CACHE_INODE_NOT_FOUND)
00262             {
00263               /* The create_arg structure contains the information "newly created directory"
00264                * to be passed to cache_inode_new_entry from cache_inode_create */
00265               create_arg.newly_created_dir = TRUE;
00266 
00267               /* Create the directory */
00268               if((dir_pentry = cache_inode_create(parent_pentry,
00269                                                   &dir_name,
00270                                                   DIRECTORY,
00271                                                   mode,
00272                                                   &create_arg,
00273                                                   &attr,
00274                                                   pcontext, &cache_status)) != NULL)
00275                 {
00276                   /*
00277                    * Get the FSAL handle for this entry
00278                    */
00279                   pfsal_handle = &dir_pentry->handle;
00280 
00281                   if(preq->rq_vers == NFS_V2)
00282                     {
00283                       DIROP2resok *d2ok = &pres->res_dirop2.DIROP2res_u.diropok;
00284 
00285                       /* Build file handle */
00286                       if(!nfs2_FSALToFhandle(&d2ok->file, pfsal_handle, pexport))
00287                         pres->res_dirop2.status = NFSERR_IO;
00288                       else
00289                         {
00290                           /*
00291                            * Build entry
00292                            * attributes
00293                            */
00294                           if(nfs2_FSALattr_To_Fattr(pexport, &attr,
00295                                                     &d2ok->attributes) == 0)
00296                             pres->res_dirop2.status = NFSERR_IO;
00297                           else
00298                             pres->res_dirop2.status = NFS_OK;
00299                         }
00300                     }
00301                   else
00302                     {
00303                       MKDIR3resok *d3ok = &pres->res_mkdir3.MKDIR3res_u.resok;
00304 
00305                       /* Build file handle */
00306                       pres->res_mkdir3.status =
00307                           nfs3_AllocateFH(&d3ok->obj.post_op_fh3_u.handle);
00308                       if(pres->res_mkdir3.status !=  NFS3_OK)
00309                         {
00310                           rc = NFS_REQ_OK;
00311                           goto out;
00312                         }
00313 
00314                       if(nfs3_FSALToFhandle(&d3ok->obj.post_op_fh3_u.handle,
00315                                             pfsal_handle, pexport) == 0)
00316                         {
00317                           gsh_free(d3ok->obj.post_op_fh3_u.handle.data.data_val);
00318                           pres->res_mkdir3.status = NFS3ERR_INVAL;
00319                           rc = NFS_REQ_OK;
00320                           goto out;
00321                         }
00322 
00323                       /* Set Post Op Fh3 structure */
00324                       d3ok->obj.handle_follows = TRUE;
00325 
00326                       /*
00327                        * Build entry attributes 
00328                        */
00329                       nfs_SetPostOpAttr(pexport, &attr, &d3ok->obj_attributes);
00330 
00331                       /* Get the attributes of the parent after the operation */
00332                       attr_parent_after = parent_pentry->attributes;
00333 
00334                       /*
00335                        * Build Weak Cache Coherency data 
00336                        */
00337                       nfs_SetWccData(pexport, ppre_attr, &attr_parent_after,
00338                                      &d3ok->dir_wcc);
00339 
00340                       pres->res_mkdir3.status = NFS3_OK;
00341                     }
00342                   rc = NFS_REQ_OK;
00343                   goto out;
00344                 }
00345             }                   /* If( cache_status_lookup == CACHE_INODE_NOT_FOUND ) */
00346           else
00347             {
00348               /* object already exists or failure during lookup */
00349               if(cache_status_lookup == CACHE_INODE_SUCCESS)
00350                 {
00351                   /* Trying to create a file that already exists */
00352                   cache_status = CACHE_INODE_ENTRY_EXISTS;
00353 
00354                   switch (preq->rq_vers)
00355                     {
00356                     case NFS_V2:
00357                       pres->res_dirop2.status = NFSERR_EXIST;
00358                       break;
00359 
00360                     case NFS_V3:
00361                       pres->res_mkdir3.status = NFS3ERR_EXIST;
00362                       break;
00363                     }
00364                 }
00365               else
00366                 {
00367                   /* Server fault */
00368                   cache_status = cache_status_lookup;
00369 
00370                   switch (preq->rq_vers)
00371                     {
00372                     case NFS_V2:
00373                       pres->res_dirop2.status = NFSERR_IO;
00374                       break;
00375 
00376                     case NFS_V3:
00377                       pres->res_mkdir3.status = NFS3ERR_INVAL;
00378                       break;
00379                     }
00380                 }
00381 
00382               nfs_SetFailedStatus(pcontext, pexport,
00383                                   preq->rq_vers,
00384                                   cache_status,
00385                                   &pres->res_dirop2.status,
00386                                   &pres->res_mkdir3.status,
00387                                   NULL, NULL,
00388                                   parent_pentry,
00389                                   ppre_attr,
00390                                   &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc),
00391                                   NULL, NULL, NULL);
00392 
00393               rc = NFS_REQ_OK;
00394               goto out;
00395             }
00396         }
00397     }
00398 
00399   /* If we are here, there was an error */
00400   if(nfs_RetryableError(cache_status))
00401     {
00402       rc = NFS_REQ_DROP;
00403       goto out;
00404     }
00405   nfs_SetFailedStatus(pcontext, pexport,
00406                       preq->rq_vers,
00407                       cache_status,
00408                       &pres->res_dirop2.status,
00409                       &pres->res_mkdir3.status,
00410                       NULL, NULL,
00411                       parent_pentry,
00412                       ppre_attr,
00413                       &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc), NULL, NULL, NULL);
00414 
00415   rc = NFS_REQ_OK;
00416 
00417 out:
00418   /* return references */
00419   if (dir_pentry)
00420       cache_inode_put(dir_pentry);
00421 
00422   if (parent_pentry)
00423       cache_inode_put(parent_pentry);
00424 
00425   return (rc);
00426 }
00427 
00436 void nfs_Mkdir_Free(nfs_res_t * resp)
00437 {
00438   if((resp->res_mkdir3.status == NFS3_OK) &&
00439      (resp->res_mkdir3.MKDIR3res_u.resok.obj.handle_follows == TRUE))
00440     gsh_free(resp->res_mkdir3.MKDIR3res_u.resok.obj
00441              .post_op_fh3_u.handle.data.data_val);
00442 }                               /* nfs_Mkdir_Free */