nfs-ganesha 1.4
|
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 */