nfs-ganesha 1.4

nfs_Setattr.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 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039 
00040 #ifdef _SOLARIS
00041 #include "solaris_port.h"
00042 #endif
00043 
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_proto_tools.h"
00063 
00082 int nfs_Setattr(nfs_arg_t *parg,
00083                 exportlist_t *pexport,
00084                 fsal_op_context_t *pcontext,
00085                 nfs_worker_data_t *pworker,
00086                 struct svc_req *preq,
00087                 nfs_res_t *pres)
00088 {
00089   sattr3 new_attributes3;
00090   sattr2 new_attributes2;
00091   fsal_attrib_list_t setattr;
00092   cache_entry_t *pentry = NULL;
00093   fsal_attrib_list_t pre_attr;
00094   fsal_attrib_list_t trunc_attr;
00095   fsal_attrib_list_t *ppre_attr;
00096   cache_inode_status_t cache_status;
00097   int do_trunc = FALSE;
00098   int rc = NFS_REQ_OK;
00099 
00100   if(isDebug(COMPONENT_NFSPROTO))
00101     {
00102       char str[LEN_FH_STR];
00103       nfs_FhandleToStr(preq->rq_vers,
00104                        &(parg->arg_setattr2.file),
00105                        &(parg->arg_setattr3.object),
00106                        NULL,
00107                        str);
00108       LogDebug(COMPONENT_NFSPROTO,
00109                "REQUEST PROCESSING: Calling nfs_Setattr handle: %s", str);
00110     }
00111 
00112   if(preq->rq_vers == NFS_V3)
00113     {
00114       /* to avoid setting it on each error case */
00115       pres->res_setattr3.SETATTR3res_u.resfail.obj_wcc.before.attributes_follow = FALSE;
00116       pres->res_setattr3.SETATTR3res_u.resfail.obj_wcc.after.attributes_follow = FALSE;
00117       ppre_attr = NULL;
00118     }
00119 
00120   /* Convert file handle into a vnode */
00121   if((pentry = nfs_FhandleToCache(preq->rq_vers,
00122                                   &(parg->arg_setattr2.file),
00123                                   &(parg->arg_setattr3.object),
00124                                   NULL,
00125                                   &(pres->res_attr2.status),
00126                                   &(pres->res_setattr3.status),
00127                                   NULL, &pre_attr, pcontext, &rc)) == NULL)
00128     {
00129       /* Stale NFS FH ? */
00130       goto out;
00131     }
00132 
00133   if((preq->rq_vers == NFS_V3) && (nfs3_Is_Fh_Xattr(&(parg->arg_setattr3.object))))
00134     {
00135       /* do nothing */
00136       nfs_SetWccData(pexport,
00137                      &pre_attr,
00138                      &pre_attr, &(pres->res_setattr3.SETATTR3res_u.resok.obj_wcc));
00139 
00140       pres->res_setattr3.status = NFS3_OK;
00141       rc = NFS_REQ_OK;
00142       goto out;
00143     }
00144 
00145   /* get directory attributes before action (for V3 reply) */
00146   ppre_attr = &pre_attr;
00147 
00148   switch (preq->rq_vers)
00149     {
00150     case NFS_V2:
00151 
00152       new_attributes2 = parg->arg_setattr2.attributes;
00153       /*
00154        * Check for 2Gb limit in V2 
00155        */
00156       if((parg->arg_setattr2.attributes.size != (u_int) - 1) &&
00157          (pre_attr.filesize > NFS2_MAX_FILESIZE))
00158         {
00159           /*
00160            *  They are trying to set the size, the
00161            *  file is >= 2GB and V2 clients don't
00162            *  understand filesizes >= 2GB, so we
00163            *  don't allow them to alter them in any
00164            *  way.
00165            */
00166           pres->res_attr2.status = NFSERR_FBIG;
00167           rc = NFS_REQ_OK;
00168           goto out;
00169         }
00170 
00171       if(nfs2_Sattr_To_FSALattr(&setattr, &new_attributes2) == 0)
00172         {
00173           pres->res_attr2.status = NFSERR_IO;
00174           rc = NFS_REQ_OK;
00175           goto out;
00176         }
00177 
00178       if(new_attributes2.size != (u_int) - 1)
00179         do_trunc = TRUE;
00180 
00181       break;
00182 
00183     case NFS_V3:
00184       new_attributes3 = parg->arg_setattr3.new_attributes;
00185 
00186       if(parg->arg_setattr3.guard.check == TRUE)
00187         {
00188           /* This pack of lines implements the "guard check" setattr.
00189            * This feature of nfsv3 is used to avoid several setattr 
00190            * to occur concurently on the same object, from different clients */
00191           fattr3 attributes;
00192 
00193           if(nfs3_FSALattr_To_PartialFattr(ppre_attr, FSAL_ATTR_CTIME, &attributes) == 0)
00194             {
00195               pres->res_setattr3.status = NFS3ERR_INVAL;
00196               rc = NFS_REQ_OK;
00197               goto out;
00198             }
00199           LogFullDebug(COMPONENT_NFSPROTO, "css=%d acs=%d    csn=%d acn=%d",
00200                  parg->arg_setattr3.guard.sattrguard3_u.obj_ctime.seconds,
00201                  attributes.ctime.seconds,
00202                  parg->arg_setattr3.guard.sattrguard3_u.obj_ctime.nseconds,
00203                  attributes.ctime.nseconds);
00204 
00205           if((parg->arg_setattr3.guard.sattrguard3_u.obj_ctime.seconds !=
00206               attributes.ctime.seconds)
00207              || (parg->arg_setattr3.guard.sattrguard3_u.obj_ctime.nseconds !=
00208                  attributes.ctime.nseconds))
00209             {
00210               pres->res_setattr3.status = NFS3ERR_NOT_SYNC;
00211               rc = NFS_REQ_OK;
00212               goto out;
00213             }
00214         }
00215 
00216       /* 
00217        * Conversion to FSAL attributes 
00218        */
00219       if(nfs3_Sattr_To_FSALattr(&setattr, &new_attributes3) == 0)
00220         {
00221           pres->res_setattr3.status = NFS3ERR_INVAL;
00222           rc = NFS_REQ_OK;
00223           goto out;
00224         }
00225 
00226       if(new_attributes3.size.set_it)
00227         {
00228           do_trunc = TRUE;
00229         }
00230 
00231       break;
00232     }
00233 
00234   /*
00235    * trunc may change Xtime so we have to start with trunc and finish
00236    * by the mtime and atime 
00237    */
00238   if(do_trunc)
00239     {
00240       /* Should not be done on a directory */
00241       if(pentry->type == DIRECTORY)
00242         cache_status = CACHE_INODE_IS_A_DIRECTORY;
00243       else
00244         {
00245           cache_status = cache_inode_truncate(pentry,
00246                                               setattr.filesize,
00247                                               &trunc_attr,
00248                                               pcontext, &cache_status);
00249           setattr.asked_attributes &= ~FSAL_ATTR_SPACEUSED;
00250           setattr.asked_attributes &= ~FSAL_ATTR_SIZE;
00251         }
00252     }
00253   else
00254     cache_status = CACHE_INODE_SUCCESS;
00255 
00256   if(cache_status == CACHE_INODE_SUCCESS)
00257     {
00258       /* Add code to support partially completed setattr */
00259       if(do_trunc)
00260         {
00261           if(setattr.asked_attributes != 0)
00262             {
00263               cache_status = cache_inode_setattr(pentry,
00264                                                  &setattr,
00265                                                  pcontext, &cache_status);
00266             }
00267           else
00268             {
00269               cache_status = CACHE_INODE_SUCCESS;
00270               setattr = trunc_attr;
00271             }
00272 
00273         }
00274       else
00275         cache_status = cache_inode_setattr(pentry,
00276                                            &setattr,
00277                                            pcontext, &cache_status);
00278     }
00279 
00280   if(cache_status == CACHE_INODE_SUCCESS)
00281     {
00282       /* Set the NFS return */
00283       switch (preq->rq_vers)
00284         {
00285         case NFS_V2:
00286           /* Copy data from vattr to Attributes */
00287           if(nfs2_FSALattr_To_Fattr
00288              (pexport, &setattr, &(pres->res_attr2.ATTR2res_u.attributes)) == 0)
00289             pres->res_attr2.status = NFSERR_IO;
00290           else
00291             pres->res_attr2.status = NFS_OK;
00292           break;
00293 
00294         case NFS_V3:
00295           /* Build Weak Cache Coherency data */
00296           nfs_SetWccData(pexport,
00297                          ppre_attr,
00298                          &setattr, &(pres->res_setattr3.SETATTR3res_u.resok.obj_wcc));
00299 
00300           pres->res_setattr3.status = NFS3_OK;
00301           break;
00302         }
00303 
00304       rc = NFS_REQ_OK;
00305       goto out;
00306     }
00307 
00308   LogFullDebug(COMPONENT_NFSPROTO, "nfs_Setattr: failed");
00309 
00310   /* If we are here, there was an error */
00311   if(nfs_RetryableError(cache_status))
00312   {
00313     rc = NFS_REQ_DROP;
00314     goto out;
00315   }
00316 
00317   nfs_SetFailedStatus(pcontext, pexport,
00318                       preq->rq_vers,
00319                       cache_status,
00320                       &pres->res_attr2.status,
00321                       &pres->res_setattr3.status,
00322                       NULL, NULL,
00323                       pentry,
00324                       ppre_attr,
00325                       &(pres->res_setattr3.SETATTR3res_u.resfail.obj_wcc),
00326                       NULL, NULL, NULL);
00327 
00328   rc = NFS_REQ_OK;
00329 
00330 out:
00331   /* return references */
00332   if (pentry)
00333       cache_inode_put(pentry);
00334 
00335   return (rc);
00336 
00337 }                               /* nfs_Setattr */
00338 
00347 void nfs_Setattr_Free(nfs_res_t * resp)
00348 {
00349   /* Nothing to do here */
00350   return;
00351 }                               /* nfs_Setattr_Free */