nfs-ganesha 1.4

nfs3_Mknod.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 
00045 #include <stdio.h>
00046 #include <string.h>
00047 #include <pthread.h>
00048 #include <fcntl.h>
00049 #include <sys/file.h>           /* for having FNDELAY */
00050 #include "HashData.h"
00051 #include "HashTable.h"
00052 #include "log.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_proto_tools.h"
00062 #include "nfs_tools.h"
00063 
00081 int nfs3_Mknod(nfs_arg_t *parg,
00082                exportlist_t *pexport,
00083                fsal_op_context_t *pcontext,
00084                nfs_worker_data_t *pworker,
00085                struct svc_req *preq,
00086                nfs_res_t * pres)
00087 {
00088   cache_entry_t *parent_pentry = NULL;
00089   fsal_attrib_list_t parent_attr;
00090   fsal_attrib_list_t *ppre_attr;
00091   fsal_attrib_list_t attr_parent_after;
00092   cache_inode_file_type_t parent_filetype;
00093   cache_inode_file_type_t nodetype;
00094   char *str_file_name = NULL;
00095   fsal_name_t file_name;
00096   cache_inode_status_t cache_status;
00097   cache_inode_status_t cache_status_lookup;
00098   fsal_accessmode_t mode = 0;
00099   cache_entry_t *node_pentry = NULL;
00100   fsal_attrib_list_t attr;
00101   cache_inode_create_arg_t create_arg;
00102   fsal_handle_t *pfsal_handle;
00103   int rc = NFS_REQ_OK;
00104 
00105 #ifdef _USE_QUOTA
00106   fsal_status_t fsal_status ;
00107 #endif
00108 
00109   memset(&create_arg, 0, sizeof(create_arg));
00110   if(isDebug(COMPONENT_NFSPROTO))
00111     {
00112       char str[LEN_FH_STR];
00113       sprint_fhandle3(str, &(parg->arg_mknod3.where.dir));
00114       LogDebug(COMPONENT_NFSPROTO,
00115                "REQUEST PROCESSING: Calling nfs3_Mknod handle: %s name: %s",
00116                str, parg->arg_mknod3.where.name);
00117     }
00118 
00119   /* to avoid setting them on each error case */
00120 
00121   pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc.before.attributes_follow = FALSE;
00122   pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc.after.attributes_follow = FALSE;
00123   ppre_attr = NULL;
00124 
00125   /* retrieve parent entry */
00126 
00127   if((parent_pentry = nfs_FhandleToCache(preq->rq_vers,
00128                                          NULL,
00129                                          &(parg->arg_mknod3.where.dir),
00130                                          NULL,
00131                                          NULL,
00132                                          &(pres->res_mknod3.status),
00133                                          NULL,
00134                                          &parent_attr,
00135                                          pcontext, &rc)) == NULL)
00136     {
00137       /* Stale NFS FH ? */
00138       return rc;
00139     }
00140 
00141   /* get directory attributes before action (for V3 reply) */
00142   ppre_attr = &parent_attr;
00143 
00144   /* Extract the filetype */
00145   parent_filetype = cache_inode_fsal_type_convert(parent_attr.type);
00146 
00147   /*
00148    * Sanity checks: new node name must be non-null; parent must be a
00149    * directory. 
00150    */
00151   if(parent_filetype != DIRECTORY)
00152     {
00153       pres->res_mknod3.status = NFS3ERR_NOTDIR;
00154       rc = NFS_REQ_OK;
00155       goto out;
00156     }
00157 
00158   str_file_name = parg->arg_mknod3.where.name;
00159 
00160   switch (parg->arg_mknod3.what.type)
00161     {
00162     case NF3CHR:
00163     case NF3BLK:
00164 
00165       if(parg->arg_mknod3.what.mknoddata3_u.device.dev_attributes.mode.set_it)
00166         mode =
00167             (fsal_accessmode_t) parg->arg_mknod3.what.mknoddata3_u.device.dev_attributes.
00168             mode.set_mode3_u.mode;
00169       else
00170         mode = (fsal_accessmode_t) 0;
00171 
00172       create_arg.dev_spec.major =
00173           parg->arg_mknod3.what.mknoddata3_u.device.spec.specdata1;
00174       create_arg.dev_spec.minor =
00175           parg->arg_mknod3.what.mknoddata3_u.device.spec.specdata2;
00176 
00177       break;
00178 
00179     case NF3FIFO:
00180     case NF3SOCK:
00181 
00182       if(parg->arg_mknod3.what.mknoddata3_u.pipe_attributes.mode.set_it)
00183         mode =
00184             (fsal_accessmode_t) parg->arg_mknod3.what.mknoddata3_u.pipe_attributes.mode.
00185             set_mode3_u.mode;
00186       else
00187         mode = (fsal_accessmode_t) 0;
00188 
00189       create_arg.dev_spec.major = 0;
00190       create_arg.dev_spec.minor = 0;
00191 
00192       break;
00193 
00194     default:
00195       pres->res_mknod3.status = NFS3ERR_BADTYPE;
00196       rc = NFS_REQ_OK;
00197       goto out;
00198     }
00199 
00200   switch (parg->arg_mknod3.what.type)
00201     {
00202     case NF3CHR:
00203       nodetype = CHARACTER_FILE;
00204       break;
00205     case NF3BLK:
00206       nodetype = BLOCK_FILE;
00207       break;
00208     case NF3FIFO:
00209       nodetype = FIFO_FILE;
00210       break;
00211     case NF3SOCK:
00212       nodetype = SOCKET_FILE;
00213       break;
00214     default:
00215       pres->res_mknod3.status = NFS3ERR_BADTYPE;
00216       rc = NFS_REQ_OK;
00217       goto out;
00218     }
00219 
00220   //if(str_file_name == NULL || strlen(str_file_name) == 0)
00221   if(str_file_name == NULL || *str_file_name == '\0' )
00222     {
00223       pres->res_mknod3.status = NFS3ERR_INVAL;
00224       rc = NFS_REQ_OK;
00225       goto out;
00226     }
00227 
00228 #ifdef _USE_QUOTA
00229     /* if quota support is active, then we should check is the FSAL allows inode creation or not */
00230     fsal_status = FSAL_check_quota( pexport->fullpath, 
00231                                     FSAL_QUOTA_INODES,
00232                                     FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ;
00233     if( FSAL_IS_ERROR( fsal_status ) )
00234      {
00235         pres->res_mknod3.status = NFS3ERR_DQUOT;
00236        return NFS_REQ_OK;
00237      }
00238 #endif /* _USE_QUOTA */
00239 
00240 
00241   /* convert node name */
00242 
00243   if((cache_status = cache_inode_error_convert(FSAL_str2name(str_file_name,
00244                                                              FSAL_MAX_NAME_LEN,
00245                                                              &file_name))) ==
00246      CACHE_INODE_SUCCESS)
00247     {
00248       /*
00249        * Lookup node to see if it exists.  If so, use it.  Otherwise
00250        * create a new one.
00251        */
00252       node_pentry = cache_inode_lookup(parent_pentry,
00253                                        &file_name,
00254                                        &attr,
00255                                        pcontext,
00256                                        &cache_status_lookup);
00257 
00258       if(cache_status_lookup == CACHE_INODE_NOT_FOUND)
00259         {
00260 
00261           /* Create the node */
00262 
00263           if((node_pentry = cache_inode_create(parent_pentry,
00264                                                &file_name,
00265                                                nodetype,
00266                                                mode,
00267                                                &create_arg,
00268                                                &attr,
00269                                                pcontext,
00270                                                &cache_status)) != NULL)
00271             {
00272               MKNOD3resok *rok = &pres->res_mknod3.MKNOD3res_u.resok;
00273               /*
00274                * Get the FSAL handle for this entry
00275                */
00276               pfsal_handle = &node_pentry->handle;
00277 
00278               /* Build file handle */
00279               pres->res_mknod3.status =
00280                     nfs3_AllocateFH(&rok->obj.post_op_fh3_u.handle);
00281               if(pres->res_mknod3.status !=  NFS3_OK)
00282                 return NFS_REQ_OK;
00283 
00284               if(nfs3_FSALToFhandle(&rok->obj.post_op_fh3_u.handle,
00285                                     pfsal_handle, pexport) == 0)
00286                 {
00287                   gsh_free(rok->obj.post_op_fh3_u.handle.data.data_val);
00288                   pres->res_mknod3.status = NFS3ERR_INVAL;
00289                   rc = NFS_REQ_OK;
00290                   goto out;
00291                 }
00292 
00293               /* Set Post Op Fh3 structure */
00294               rok->obj.handle_follows = TRUE;
00295 
00296               /* Build entry attributes */
00297               nfs_SetPostOpAttr(pexport, &attr, &rok->obj_attributes);
00298 
00299               /* Get the attributes of the parent after the operation */
00300               attr_parent_after = parent_pentry->attributes;
00301 
00302               /* Build Weak Cache Coherency data */
00303               nfs_SetWccData(pexport, ppre_attr, &attr_parent_after,
00304                              &rok->dir_wcc);
00305 
00306               pres->res_mknod3.status = NFS3_OK;
00307 
00308               rc = NFS_REQ_OK;
00309               goto out;
00310             }
00311           /* mknod sucess */
00312         }                       /* not found */
00313       else
00314         {
00315           /* object already exists or failure during lookup */
00316           if(cache_status_lookup == CACHE_INODE_SUCCESS)
00317             {
00318               /* Trying to create an entry that already exists */
00319               cache_status = CACHE_INODE_ENTRY_EXISTS;
00320               pres->res_mknod3.status = NFS3ERR_EXIST;
00321             }
00322           else
00323             {
00324               /* Server fault */
00325               cache_status = cache_status_lookup;
00326               pres->res_mknod3.status = NFS3ERR_INVAL;
00327             }
00328 
00329           nfs_SetFailedStatus(pcontext, pexport,
00330                               preq->rq_vers,
00331                               cache_status,
00332                               NULL,
00333                               &pres->res_mknod3.status,
00334                               NULL, NULL,
00335                               parent_pentry,
00336                               ppre_attr,
00337                               &(pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc),
00338                               NULL, NULL, NULL);
00339 
00340           rc = NFS_REQ_OK;
00341           goto out;
00342         }
00343 
00344     }
00345 
00346   /* convertion OK */
00347   /* If we are here, there was an error */
00348   if(nfs_RetryableError(cache_status))
00349     {
00350       rc = NFS_REQ_DROP;
00351       goto out;
00352     }
00353   nfs_SetFailedStatus(pcontext, pexport,
00354                       preq->rq_vers,
00355                       cache_status,
00356                       NULL,
00357                       &pres->res_mknod3.status,
00358                       NULL, NULL,
00359                       parent_pentry,
00360                       ppre_attr,
00361                       &(pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc), NULL, NULL, NULL);
00362 
00363   rc = NFS_REQ_OK;
00364 
00365 out:
00366   /* return references */
00367   if (parent_pentry)
00368       cache_inode_put(parent_pentry);
00369 
00370   if (node_pentry)
00371       cache_inode_put(node_pentry);
00372 
00373   return (rc);
00374 
00375 }                               /* nfs3_Mknod */
00376 
00385 void nfs3_Mknod_Free(nfs_res_t * pres)
00386 {
00387   if((pres->res_mknod3.status == NFS3_OK) &&
00388      (pres->res_mknod3.MKNOD3res_u.resok.obj.handle_follows == TRUE))
00389     gsh_free(pres->res_mknod3.MKNOD3res_u.resok.obj.post_op_fh3_u
00390              .handle.data.data_val);
00391 
00392 }                               /* nfs3_Mknod_Free */