XrdFfsPosix.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /* XrdFfsPosix.cc C wrapper to some of the Xrootd Posix library functions     */
00003 /*                                                                            */
00004 /* (c) 2010 by the Board of Trustees of the Leland Stanford, Jr., University  */
00005 /*                            All Rights Reserved                             */
00006 /* Author: Wei Yang (SLAC National Accelerator Laboratory, 2009)              */
00007 /*         Contract DE-AC02-76-SFO0515 with the Department of Energy          */
00008 /******************************************************************************/
00009 
00010 #define _FILE_OFFSET_BITS 64
00011 #include <errno.h>
00012 #include <stdio.h>
00013 #include <string.h>
00014 #include <sys/types.h>
00015 
00016 #if !defined(__solaris__)
00017 #include <sys/xattr.h> 
00018 #endif
00019 
00020 #ifndef ENOATTR 
00021   #define ENOATTR ENODATA 
00022 #endif
00023 
00024 #include <iostream>
00025 #include <libgen.h>
00026 #include <unistd.h>
00027 #include <stdlib.h>
00028 #include <syslog.h>
00029 #include "XrdFfs/XrdFfsPosix.hh"
00030 #include "XrdPosix/XrdPosixXrootd.hh"
00031 #include "XrdFfs/XrdFfsMisc.hh"
00032 #include "XrdFfs/XrdFfsDent.hh"
00033 #include "XrdFfs/XrdFfsQueue.hh"
00034 
00035 #ifdef __cplusplus
00036   extern "C" {
00037 #endif
00038 
00039 int XrdFfsPosix_stat(const char *path, struct stat *buf)
00040 {
00041     int rc; 
00042     errno = 0;
00043     rc = XrdPosixXrootd::Stat(path, buf);
00044     if (rc == 0 && S_ISBLK(buf->st_mode)) /* If 'buf' come from HPSS, xrootd will return it as a block device! */
00045     {                                     /* So we re-mark it to a regular file */
00046         buf->st_mode &= 0007777;
00047         if ( buf->st_mode & S_IXUSR )
00048             buf->st_mode |= 0040000;   /* a directory */
00049         else
00050             buf->st_mode |= 0100000;   /* a file */
00051     }
00052     return rc;
00053 }
00054 
00055 DIR *XrdFfsPosix_opendir(const char *path)
00056 {
00057     return XrdPosixXrootd::Opendir(path);
00058 }
00059 
00060 struct dirent *XrdFfsPosix_readdir(DIR *dirp)
00061 {
00062     return XrdPosixXrootd::Readdir(dirp);
00063 }
00064 
00065 int XrdFfsPosix_closedir(DIR *dirp)
00066 {
00067     return XrdPosixXrootd::Closedir(dirp);
00068 }
00069 
00070 int XrdFfsPosix_mkdir(const char *path, mode_t mode)
00071 {
00072     return XrdPosixXrootd::Mkdir(path, mode);
00073 }
00074 
00075 int XrdFfsPosix_rmdir(const char *path)
00076 {
00077 /* Note: Xrootd returns ENOSYS rather than ENOTEMPTY when a directory is not empty */
00078     return XrdPosixXrootd::Rmdir(path);
00079 }
00080 
00081 int XrdFfsPosix_open(const char *path, int oflags, mode_t mode)
00082 {
00083     return XrdPosixXrootd::Open(path, oflags, mode);
00084 }
00085 
00086 int XrdFfsPosix_close(int fildes)
00087 {
00088     return XrdPosixXrootd::Close(fildes);
00089 }
00090 
00091 off_t XrdFfsPosix_lseek(int fildes, off_t offset, int whence)
00092 {
00093     return XrdPosixXrootd::Lseek(fildes, (long long)offset, whence);
00094 }
00095 
00096 ssize_t XrdFfsPosix_read(int fildes, void *buf, size_t nbyte)
00097 {
00098     return XrdPosixXrootd::Read(fildes, buf, nbyte);
00099 }
00100 
00101 ssize_t XrdFfsPosix_pread(int fildes, void *buf, size_t nbyte, off_t offset)
00102 {
00103     return XrdPosixXrootd::Pread(fildes, buf, nbyte, (long long)offset);
00104 }
00105 
00106 ssize_t XrdFfsPosix_write(int fildes, const void *buf, size_t nbyte)
00107 {
00108     return XrdPosixXrootd::Write(fildes, buf, nbyte);
00109 }
00110 
00111 ssize_t XrdFfsPosix_pwrite(int fildes, const void *buf, size_t nbyte, off_t offset)
00112 {
00113     return XrdPosixXrootd::Pwrite(fildes, buf, nbyte, (long long) offset);
00114 }
00115 
00116 int XrdFfsPosix_fsync(int fildes)
00117 {
00118     return XrdPosixXrootd::Fsync(fildes);
00119 }
00120 
00121 int XrdFfsPosix_unlink(const char *path)
00122 {
00123     return XrdPosixXrootd::Unlink(path);
00124 }
00125 
00126 int XrdFfsPosix_rename(const char *oldpath, const char *newpath)
00127 {
00128     return XrdPosixXrootd::Rename(oldpath, newpath);
00129 }
00130 
00131 int XrdFfsPosix_ftruncate(int fildes, off_t offset)
00132 {
00133     return XrdPosixXrootd::Ftruncate(fildes, offset);
00134 }
00135 int XrdFfsPosix_truncate(const char *path, off_t Size)
00136 {
00137     return XrdPosixXrootd::Truncate(path, Size);
00138 }
00139 
00140 long long XrdFfsPosix_getxattr(const char *path, const char *name, void *value, unsigned long long size)
00141 {
00142     int bufsize;
00143     char xattrbuf[1024], nameclass[128], *namesubclass;
00144     char *token, *key, *val;
00145     char *lasts_xattr[256], *lasts_tokens[128];
00146 
00147 /*
00148     Xrootd only support two names: xroot.space and xroot.xattr. We add support of xroot.space.*
00149     such as xroot.space.oss.cgroup etc.
00150  */
00151     strncpy(nameclass, name, 11);
00152     nameclass[11] = '\0';
00153 
00154     if (strcmp(nameclass, "xroot.space") != 0 && strcmp(nameclass, "xroot.xattr") != 0)
00155     {
00156         errno = ENOATTR;
00157         return -1;
00158     }
00159 
00160     bufsize = XrdPosixXrootd::Getxattr(path, nameclass, xattrbuf, size);
00161     if (bufsize == -1) return -1;
00162 
00163     if (strlen(name) > 11) 
00164     {
00165         strcpy(nameclass, name);
00166         namesubclass = &nameclass[12];
00167     }
00168     else  /* xroot.space or xroot.xattr is provided. */ 
00169     {
00170         strcpy((char*)value, xattrbuf);
00171         return bufsize;
00172     }
00173 
00174     token = strtok_r(xattrbuf, "&", lasts_xattr);
00175     while ( token != NULL )
00176     {
00177          key = strtok_r(token, "=", lasts_tokens);
00178          val = strtok_r(NULL, "=", lasts_tokens);
00179          if (! strcmp(key, namesubclass))
00180          {
00181               strcpy((char*)value, val);
00182               return strlen(val);
00183          }
00184          token = strtok_r(NULL, "&", lasts_xattr);
00185     }    
00186     errno = ENOATTR; 
00187     return -1;
00188 }
00189 
00190 /* Posix IO functions to operation on all data servers */
00191 
00192 struct XrdFfsPosixX_deleteall_args {
00193     char *url;
00194     int *res;
00195     int *err;
00196     mode_t st_mode;
00197 };
00198 
00199 void* XrdFfsPosix_x_deleteall(void *x)
00200 {
00201     struct XrdFfsPosixX_deleteall_args* args = (struct XrdFfsPosixX_deleteall_args*) x;
00202 
00203     if (S_ISREG(args->st_mode))
00204         *(args->res) = XrdFfsPosix_unlink(args->url);
00205     else if (S_ISDIR(args->st_mode))
00206         *(args->res) = XrdFfsPosix_rmdir(args->url);
00207 
00208     *(args->err) = errno;
00209     return NULL;
00210 }
00211         
00212 int XrdFfsPosix_deleteall(const char *rdrurl, const char *path, uid_t user_uid, mode_t st_mode)
00213 {
00214     int i, nurls, res, rval;
00215     char *newurls[XrdFfs_MAX_NUM_NODES];
00216     int res_i[XrdFfs_MAX_NUM_NODES];
00217     int errno_i[XrdFfs_MAX_NUM_NODES];
00218     struct XrdFfsPosixX_deleteall_args args[XrdFfs_MAX_NUM_NODES];
00219     struct XrdFfsQueueTasks *jobs[XrdFfs_MAX_NUM_NODES];
00220 
00221     nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
00222     if (nurls < 0) rval = -1;
00223 
00224     for (i = 0; i < nurls; i++)
00225     {
00226         errno_i[i] = 0;
00227         strcat(newurls[i],path);
00228         XrdFfsMisc_xrd_secsss_editurl(newurls[i], user_uid);
00229         args[i].url = newurls[i];
00230         args[i].err = &errno_i[i];
00231         args[i].res = &res_i[i];
00232         args[i].st_mode = st_mode;
00233 #ifdef NOUSE_QUEUE
00234         XrdFfsPosix_x_deleteall((void*) &args[i]);
00235     }
00236 #else
00237         jobs[i] = XrdFfsQueue_create_task(XrdFfsPosix_x_deleteall, (void**)(&args[i]), 0);
00238     }
00239     for (i = 0; i < nurls; i++)
00240     {
00241         XrdFfsQueue_wait_task(jobs[i]);
00242         XrdFfsQueue_free_task(jobs[i]);
00243     }
00244 #endif
00245     res = -1;
00246     errno = ENOENT;
00247     for (i = 0; i < nurls; i++)
00248         if (res_i[i] == 0)
00249         {
00250             res = 0;
00251             errno = 0;
00252         }
00253         else if (res_i[i] != 0 && errno_i[i] == 125) // host is down
00254         {
00255             res = -1;
00256             errno = ETIMEDOUT;
00257             syslog(LOG_WARNING, "WARNING: unlink/rmdir(%s) failed (connection timeout)", newurls[i]);
00258             break;
00259         }
00260         else if (res_i[i] != 0 && errno_i[i] != ENOENT)
00261         {
00262             res = -1;
00263             errno = errno_i[i];
00264             syslog(LOG_WARNING, "WARNING: unlink/rmdir(%s) failed (errno = %d)", newurls[i], errno);
00265             break;
00266         }
00267 
00268     for (i = 0; i < nurls; i++)
00269         free(newurls[i]);
00270 
00271     return res; 
00272 }
00273 
00274 int XrdFfsPosix_unlinkall(const char *rdrurl, const char *path, uid_t user_uid)
00275 {
00276     return XrdFfsPosix_deleteall(rdrurl, path, user_uid, S_IFREG);
00277 }
00278 
00279 int XrdFfsPosix_rmdirall(const char *rdrurl, const char *path, uid_t user_uid)
00280 {
00281     return XrdFfsPosix_deleteall(rdrurl, path, user_uid, S_IFDIR);
00282 }
00283 
00284 int XrdFfsPosix_renameall(const char *rdrurl, const char *from, const char *to, uid_t user_uid)
00285 {
00286     int i, nurls, res, rval = 0;
00287     struct stat stbuf;
00288     char fromurl[1024], tourl[1024], *newurls[XrdFfs_MAX_NUM_NODES];
00289 
00290     nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
00291     if (nurls < 0) rval = -1;
00292 
00293     for (i = 0; i < nurls; i++)
00294     {
00295         errno = 0;
00296 
00297         fromurl[0]='\0';
00298         strcat(fromurl, newurls[i]);
00299         strcat(fromurl, from);
00300         tourl[0]='\0';
00301         strcat(tourl, newurls[i]);
00302         strcat(tourl, to);
00303 
00304         XrdFfsMisc_xrd_secsss_editurl(fromurl, user_uid);
00305         XrdFfsMisc_xrd_secsss_editurl(tourl, user_uid);
00306         res = (XrdFfsPosix_stat(fromurl, &stbuf));
00307         if (res == 0)
00308         {
00309 /* XrdFfsPosix_rename doesn't need this protection
00310             newdir = strdup(tourl);
00311             newdir = dirname(newdir);
00312             if (XrdFfsPosix_stat(newdir, &stbuf) == -1)
00313                 XrdFfsPosix_mkdir(newdir, 0777);
00314 
00315             free(newdir);
00316 */
00317             rval = XrdFfsPosix_rename(fromurl, tourl);
00318             if (rval == -1) 
00319             {
00320                 syslog(LOG_WARNING, "WARNING: rename(%s, %s) failed (errno = %d)", fromurl, tourl, errno);
00321                 break;
00322             }
00323 /* well, it will be messy if a successful rename is followed by a failed one */
00324         } 
00325     }
00326 
00327     for (i = 0; i < nurls; i++)
00328         free(newurls[i]);
00329 
00330     if (rval != 0 && errno == 0) errno = EIO;
00331     return rval;
00332 }
00333 
00334 int XrdFfsPosix_truncateall(const char *rdrurl, const char *path, off_t size, uid_t user_uid)
00335 {
00336     int i, nurls, res, rval = 0;
00337     struct stat stbuf;
00338     char *newurls[XrdFfs_MAX_NUM_NODES];
00339 
00340     nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
00341     if (nurls < 0) rval = -1;
00342 
00343     for (i = 0; i < nurls; i++)
00344     {
00345         errno = 0;
00346         strcat(newurls[i],path);
00347         XrdFfsMisc_xrd_secsss_editurl(newurls[i], user_uid);
00348         res = (XrdFfsPosix_stat(newurls[i], &stbuf));
00349         if (res == 0)
00350         {
00351             if (S_ISREG(stbuf.st_mode))
00352                 rval = XrdFfsPosix_truncate(newurls[i], size);
00353             else 
00354                 rval = -1;
00355             if (rval == -1) 
00356             {
00357                 syslog(LOG_WARNING, "WARNING: (f)truncate(%s) failed (errno = %d)", newurls[i], errno);
00358                 break;
00359             }
00360 /* again, it will be messy if a successful truncate is followed by a failed one */
00361         }
00362         else if (errno != ENOENT)
00363             rval = -1;
00364     }
00365 
00366     for (i = 0; i < nurls; i++)
00367         free(newurls[i]);
00368 
00369     if (rval != 0 && errno == 0) errno = EIO;
00370     return rval;
00371 }
00372 
00373 struct XrdFfsPosixX_readdirall_args {
00374     char *url;
00375     int *res;
00376     int *err;
00377     struct XrdFfsDentnames **dents;
00378 };
00379  
00380 /*
00381    It seems xrootd posix return dp[i] != NULL even if the dir
00382    doesn't exist on a data server. XrdFfsPosix_readdir() returns
00383    NULL in this case.
00384 
00385    Do we need some protection here? We are not in trouble so far
00386    because FUSE's _getattr will test the existance of the dir
00387    so we know that at least one data server has the directory.
00388  */
00389 void* XrdFfsPosix_x_readdirall(void* x)
00390 {
00391     struct XrdFfsPosixX_readdirall_args *args = (struct XrdFfsPosixX_readdirall_args*) x;
00392     DIR *dp;
00393     struct dirent *de;
00394 
00395 /*
00396    Xrootd's Opendir will not return NULL even under some error. For instance,
00397    when it is supposed to return ENOENT or ENOTDIR, it actually returns 
00398    EINPROGRESS (115), and DIR *dp will not be NULL.
00399  */
00400     dp = XrdFfsPosix_opendir(args->url);
00401     if ( dp == NULL && errno != 0)
00402     {
00403         *(args->err) = errno;
00404         *(args->res) = -1;
00405         if (dp != NULL)
00406             XrdFfsPosix_closedir(dp);
00407     }
00408     else
00409     {
00410         *(args->res) = 0;
00411         while ((de = XrdFfsPosix_readdir(dp)) != NULL)
00412             XrdFfsDent_names_add(args->dents, de->d_name);
00413         XrdFfsPosix_closedir(dp);
00414     }
00415     return NULL;
00416 }
00417 
00418 int XrdFfsPosix_readdirall(const char *rdrurl, const char *path, char*** direntarray, uid_t user_uid)
00419 {
00420     int i, j, n, nents, nurls; 
00421     bool hasDirLock = false;
00422 
00423     char *newurls[XrdFfs_MAX_NUM_NODES];
00424     int res_i[XrdFfs_MAX_NUM_NODES];
00425     int errno_i[XrdFfs_MAX_NUM_NODES];
00426     struct XrdFfsDentnames *dir_i[XrdFfs_MAX_NUM_NODES] = {0};
00427     struct XrdFfsPosixX_readdirall_args args[XrdFfs_MAX_NUM_NODES];
00428     struct XrdFfsQueueTasks *jobs[XrdFfs_MAX_NUM_NODES];
00429 
00430 //    for (i = 0; i < XrdFfs_MAX_NUM_NODES; i++)
00431 //        dir_i[i] = NULL;
00432 
00433     nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
00434     if (nurls < 0) 
00435     {
00436         errno = EACCES;
00437         return -1;
00438     }
00439 
00440     for (i = 0; i < nurls; i++)
00441     {
00442         errno_i[i] = 0;
00443         strcat(newurls[i], path);
00444         XrdFfsMisc_xrd_secsss_editurl(newurls[i], user_uid);
00445         args[i].url = newurls[i];
00446         args[i].err = &errno_i[i];
00447         args[i].res = &res_i[i];
00448         args[i].dents = &dir_i[i];
00449 #ifdef NOUSE_QUEUE
00450         XrdFfsPosix_x_readdirall((void*) &args[i]);
00451     }   
00452 #else
00453         jobs[i] = XrdFfsQueue_create_task(XrdFfsPosix_x_readdirall, (void**)(&args[i]), 0);
00454     }
00455     for (i = 0; i < nurls; i++)
00456     {
00457         XrdFfsQueue_wait_task(jobs[i]);
00458         XrdFfsQueue_free_task(jobs[i]);
00459     }
00460 #endif
00461 
00462     errno = 0;
00463     for (i = 0; i < nurls; i++)
00464         if (res_i[i] != 0 && errno_i[i] == 125) // when host i is down
00465         {
00466             errno = ETIMEDOUT;
00467             syslog(LOG_WARNING, "WARNING: opendir(%s) failed (connection timeout)", newurls[i]);
00468             break;
00469         }
00470 
00471     for (i = 0; i < nurls; i++)
00472         free(newurls[i]);
00473     for (i = 1; i < nurls; i++)
00474         XrdFfsDent_names_join(&dir_i[i], &dir_i[i-1]);
00475 
00476     char *last = NULL, **dnarraytmp;
00477 
00478     n = XrdFfsDent_names_extract(&dir_i[nurls-1], &dnarraytmp);
00479     *direntarray = (char **) malloc(sizeof(char*) * n);
00480 
00481 // note that dnarraytmp[] may contain redundant entries
00482 
00483     nents = 0;
00484     for (i = 0; i < n; i++)
00485     {
00486         // put DIR_LOCK to the last one to allow rm -rf to work...
00487         //
00488         if (! strcmp(dnarraytmp[i], "DIR_LOCK")) 
00489         {
00490             hasDirLock = true;
00491             continue;  
00492         }
00493 
00494         if (i != 0)   // can be used to filter out .lock .fail, etc. 
00495         {
00496             char *tmp, *tmp_dot;
00497             tmp = strdup(dnarraytmp[i]);
00498             tmp_dot = tmp + strlen(tmp) - 5;
00499 
00500             if (! strcmp(tmp_dot, ".lock") || ! strcmp(tmp_dot, ".fail"))   // filter out .lock/.fail files
00501             {
00502                 for (j = nents - 1; j >= 0; j--)
00503                 {
00504                     tmp_dot[0] = '\0';
00505                     if (! strcmp(tmp, (*direntarray)[j]))
00506                     {
00507                         tmp_dot[0] = '.';
00508                         free(tmp);
00509                         break;
00510                     }
00511                 }
00512                 if (j >= 0) continue;  // found the file cooresponding to the .lock/.fail
00513             }
00514             free(tmp);
00515         }
00516 
00517         if (last == NULL || strcmp(last, dnarraytmp[i]) != 0)
00518         {
00519             last = dnarraytmp[i];
00520             (*direntarray)[nents++] = strdup(dnarraytmp[i]);
00521         }
00522     }
00523     
00524     for (i = 0; i < n; i++) free(dnarraytmp[i]);  // do not mergo with the above because the above loop has 'break'.
00525     free(dnarraytmp);
00526 
00527 /* inject this list into dent cache */
00528 
00529     char *p;
00530     p = strdup(path);
00531     XrdFfsDent_cache_fill(p, direntarray, nents);
00532     free(p);
00533 
00534     if (hasDirLock) (*direntarray)[nents++] = strdup("DIR_LOCK");
00535 
00536     return nents;
00537 }
00538 
00539 /* 
00540    struct XrdFfsPosixX_statvfsall_args, void XrdFfsPosix_x_statvfsall(), int XrdFfsPosiXrdFfsPosix_x_statvfsall() are 
00541    organized in such a way to allow using pthread if needed
00542  */
00543 
00544 struct XrdFfsPosixX_statvfsall_args {
00545     char *url;
00546     int *res;
00547     int *err;
00548     struct statvfs *stbuf;
00549     short osscgroup;
00550 };
00551 
00552 void* XrdFfsPosix_x_statvfsall(void *x)
00553 {
00554     struct XrdFfsPosixX_statvfsall_args *args = (struct XrdFfsPosixX_statvfsall_args *)x;
00555     char xattr[256];
00556     off_t oss_size;
00557     long long llVal;
00558 
00559     *(args->res) = XrdFfsPosix_getxattr(args->url, "xroot.space.oss.space", xattr, 256);
00560     *(args->err) = errno;
00561     sscanf((const char*)xattr, "%lld", &llVal);
00562     oss_size = static_cast<off_t>(llVal);
00563     args->stbuf->f_blocks = (fsblkcnt_t) (oss_size / args->stbuf->f_bsize);
00564 //    sscanf((const char*)xattr, "%lld", &(args->stbuf->f_blocks));
00565     if (*(args->res) == -1)
00566     {
00567         args->stbuf->f_blocks = 0;
00568         args->stbuf->f_bavail = 0;
00569         args->stbuf->f_bfree = 0;
00570         return NULL;
00571     }
00572     *(args->res) = XrdFfsPosix_getxattr(args->url, "xroot.space.oss.free", xattr, 256);
00573     *(args->err) = errno;
00574     sscanf((const char*)xattr, "%lld", &llVal);
00575     oss_size = static_cast<off_t>(llVal);
00576     args->stbuf->f_bavail = (fsblkcnt_t) (oss_size / args->stbuf->f_bsize);
00577 //    sscanf((const char*)xattr, "%lld", &(args->stbuf->f_bavail));
00578     if (*(args->res) == -1)
00579     {
00580         args->stbuf->f_blocks = 0;
00581         args->stbuf->f_bavail = 0;
00582         args->stbuf->f_bfree = 0;
00583         return NULL;
00584     }
00585 
00586 /*
00587    The relation of the output of df and stbuf->f_blocks, f_bfree and f_bavail is
00588    Filesystem            Size        Used                  Avail            Use% Mounted on
00589                          f_blocks    f_blocks - f_bfree    f_bavail
00590 
00591    In the case of querying without oss.cgroup, f_bfree = f_bavail (e.g. Used is used space by all oss.space)
00592    In the case of querying with oss.cgroup, Used is used space by the specified oss.space (oss_size/f_bsize) and
00593    therefore f_bfree = f_blocks - oss_size / f_bsize (e.g. Used is oss_size / f_bsize)
00594  */
00595 
00596     if (args->osscgroup != 1)
00597         args->stbuf->f_bfree = args->stbuf->f_bavail;
00598     else
00599     {
00600         *(args->res) = XrdFfsPosix_getxattr(args->url, "xroot.space.oss.used", xattr, 256);
00601         *(args->err) = errno;
00602         sscanf((const char*)xattr, "%lld", &llVal);
00603         oss_size = static_cast<off_t>(llVal);
00604         args->stbuf->f_bfree = args->stbuf->f_blocks - (fsblkcnt_t) (oss_size / args->stbuf->f_bsize);
00605 //        args->stbuf->f_bfree = args->stbuf->f_blocks - oss_size;
00606     }
00607     return NULL;
00608 }
00609 
00610 int XrdFfsPosix_statvfsall(const char *rdrurl, const char *path, struct statvfs *stbuf, uid_t user_uid)
00611 {
00612     int i, nurls;
00613     short osscgroup;
00614 
00615     char *newurls[XrdFfs_MAX_NUM_NODES];
00616     int res_i[XrdFfs_MAX_NUM_NODES];
00617     int errno_i[XrdFfs_MAX_NUM_NODES];
00618     struct statvfs stbuf_i[XrdFfs_MAX_NUM_NODES];
00619     struct XrdFfsPosixX_statvfsall_args args[XrdFfs_MAX_NUM_NODES];
00620     struct XrdFfsQueueTasks *jobs[XrdFfs_MAX_NUM_NODES];
00621 
00622     nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
00623     if (nurls < 0)
00624     {
00625         errno = EACCES;
00626         return -1;
00627     }
00628 
00629     if (strstr(path, "oss.cgroup") != NULL)
00630         osscgroup = 1;
00631     else 
00632         osscgroup = 0;
00633     for (i = 0; i < nurls; i++)
00634     {
00635         strcat(newurls[i], path);
00636 //        XrdFfsMisc_xrd_secsss_editurl(newurls[i], user_uid);
00637         args[i].url = newurls[i];
00638         args[i].res = &res_i[i];
00639         args[i].err = &errno_i[i];
00640         stbuf_i[i].f_bsize = stbuf->f_bsize;
00641         args[i].stbuf = &(stbuf_i[i]);
00642         args[i].osscgroup = osscgroup;
00643 #ifdef NOUSE_QUEUE
00644         XrdFfsPosix_x_statvfsall((void*) &args[i]);
00645     }
00646 #else
00647         jobs[i] = XrdFfsQueue_create_task(XrdFfsPosix_x_statvfsall, (void**)(&args[i]), 0);
00648     }
00649     for (i = 0; i < nurls; i++)
00650     {
00651         XrdFfsQueue_wait_task(jobs[i]);
00652         XrdFfsQueue_free_task(jobs[i]);
00653     }
00654 #endif
00655  /*
00656    for statfs call, we don't care about return code and errno 
00657   */
00658     stbuf->f_blocks = 0;
00659     stbuf->f_bfree = 0;
00660     stbuf->f_bavail = 0;
00661     for (i = 0; i < nurls; i++)
00662     {
00663         stbuf->f_blocks += args[i].stbuf->f_blocks;
00664         stbuf->f_bavail += args[i].stbuf->f_bavail;
00665         stbuf->f_bfree += args[i].stbuf->f_bfree;
00666     }
00667 
00668     for (i = 0; i < nurls; i++)
00669         free(newurls[i]);
00670 
00671     return 0;
00672 } 
00673 
00674 /* XrdFfsPosiXrdFfsPosix_x_statall() */
00675 
00676 struct XrdFfsPosixX_statall_args {
00677     char *url;
00678     int *res;
00679     int *err;
00680     struct stat *stbuf;
00681 };
00682 
00683 void* XrdFfsPosix_x_statall(void *x)
00684 {
00685     struct XrdFfsPosixX_statall_args *args = (struct XrdFfsPosixX_statall_args *)x;
00686 
00687     *(args->res) = XrdFfsPosix_stat(args->url, args->stbuf);
00688     *(args->err) = errno;
00689     return (void *)0;
00690 }
00691 
00692 int XrdFfsPosix_statall(const char *rdrurl, const char *path, struct stat *stbuf, uid_t user_uid)
00693 {
00694     int i, res, nurls;
00695 
00696     char *newurls[XrdFfs_MAX_NUM_NODES];
00697     int res_i[XrdFfs_MAX_NUM_NODES];
00698     int errno_i[XrdFfs_MAX_NUM_NODES];
00699     struct stat stbuf_i[XrdFfs_MAX_NUM_NODES];
00700     struct XrdFfsPosixX_statall_args args[XrdFfs_MAX_NUM_NODES];
00701     struct XrdFfsQueueTasks *jobs[XrdFfs_MAX_NUM_NODES];
00702 
00703     char *p1, *p2, *dir, *file, rootpath[1024];
00704 
00705     rootpath[0] = '\0';
00706     strcat(rootpath,rdrurl);
00707     strcat(rootpath,path);
00708     p1 = strdup(path);
00709     p2 = strdup(path);
00710     dir = dirname(p1);
00711     file = basename(p2);
00712 
00713     if (XrdFfsDent_cache_search(dir, file))
00714     {
00715          XrdFfsMisc_xrd_secsss_editurl(rootpath, user_uid);
00716          res = XrdFfsPosix_stat(rootpath, stbuf);
00717 // maybe a data server is down since the last _readdir()? in that case, continue 
00718 // we also saw a case where redirectors report the file exist but meta redirector report
00719 // that the file doesn't exist, and we need to continue at here
00720          if (res == 0) 
00721          {
00722              free(p1);
00723              free(p2);
00724              return 0;
00725          }
00726     }
00727     free(p1);
00728     free(p2);    
00729 
00730     nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
00731 
00732     for (i = 0; i < nurls; i++)
00733     {
00734         strcat(newurls[i], path);
00735         XrdFfsMisc_xrd_secsss_editurl(newurls[i], user_uid);
00736         args[i].url = newurls[i];
00737         args[i].res = &res_i[i];
00738         args[i].err = &errno_i[i];
00739         args[i].stbuf = &(stbuf_i[i]);
00740 #ifdef NOUSE_QUEUE
00741         XrdFfsPosix_x_statall((void*) &args[i]);
00742     }
00743 #else
00744         jobs[i] = XrdFfsQueue_create_task(XrdFfsPosix_x_statall, (void**)(&args[i]), 0);
00745     }
00746     for (i = 0; i < nurls; i++)
00747     {
00748         XrdFfsQueue_wait_task(jobs[i]);
00749         XrdFfsQueue_free_task(jobs[i]);
00750     }
00751 #endif
00752     res = -1;
00753     errno = ENOENT;
00754     for (i = 0; i < nurls; i++)
00755         if (res_i[i] == 0) 
00756         {
00757             res = 0;
00758             errno = 0;
00759             memcpy((void*)stbuf, (void*)(&stbuf_i[i]), sizeof(struct stat));
00760             break;
00761         }
00762         else if (res_i[i] != 0 && errno_i[i] == 125) // when host i is down
00763         {
00764             res = -1;
00765             errno = ETIMEDOUT;
00766             syslog(LOG_WARNING, "WARNING: stat(%s) failed (connection timeout)", newurls[i]);
00767         }
00768 
00769     for (i = 0; i < nurls; i++)
00770         free(newurls[i]);
00771 
00772     return res;
00773 }
00774 
00775 #ifdef __cplusplus
00776   }
00777 #endif

Generated on Tue Jul 5 14:46:34 2011 for ROOT_528-00b_version by  doxygen 1.5.1