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 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 */