40 #include <sys/param.h>
41 #include <sys/types.h>
45 #include <sys/sysmacros.h>
79 double XrdOssCache::fuzAlloc= 0.0;
80 long long XrdOssCache::minAlloc= 0;
82 int XrdOssCache::ovhAlloc= 0;
83 int XrdOssCache::Quotas = 0;
84 int XrdOssCache::Usage = 0;
110 if (!(pact= realpath(fsp,0))) pact = path;
111 size =
static_cast<long long>(fsbuff.f_blocks)
112 *
static_cast<long long>(fsbuff.FS_BLKSZ);
113 frsz =
static_cast<long long>(fsbuff.f_bavail)
114 *
static_cast<long long>(fsbuff.FS_BLKSZ);
127 std::map<dev_t, devID>::iterator it =
dev2ID.find(fsID);
129 {bdevID =
static_cast<unsigned short>(it->second.bdevID);
130 if (it->second.partID == 0) it->second.partID =
prtNMax++;
131 partID =
static_cast<unsigned short>(it->second.partID);
132 devN = it->second.nDev;
135 partID =
static_cast<unsigned short>(
prtNMax++);
151 static const mode_t theMode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
167 if (fsp) {retc = EEXIST;
return;}
171 if (!(fsOpts & isXA)) path = strdup(fsPath);
173 if (
mkdir(path, theMode) && errno != EEXIST) {retc=errno;
return;}
176 group = strdup(fsGrp);
183 if (FS_Stat(fsPath, &fsbuff) ||
stat(fsPath, &sfbuff)) {retc=errno;
return;}
188 while(fdp) {
if (fdp->fsid == sfbuff.st_dev)
break; fdp = fdp->
next;}
216 while(fsgroup && strcmp(group, fsgroup->group)) fsgroup = fsgroup->
next;
225 for (n = 0; n < fsgroup->fsNum && fdp != fsgroup->fsVec[n].fsP; n++);
226 if (n >= fsgroup->fsNum)
229 fsAP = &(fsgroup->fsVec[fsgroup->fsNum++]);
233 }
else fsAP = &(fsgroup->fsVec[n]);
237 n = (fsAP->
apNum + 2) *
sizeof(
char *);
238 fsAP->
apVec = (
const char **)realloc((
void *)fsAP->
apVec, n);
258 if (FS_Stat(fsPath, &fsbuff) ||
stat(fsPath, &sfbuff))
return -errno;
263 while(fdp) {
if (fdp->fsid == sfbuff.st_dev)
break; fdp = fdp->
next;}
287 {
if (FS_Stat(path, &fsbuff))
return -1;
288 Size =
static_cast<long long>(fsbuff.f_blocks)
289 *
static_cast<long long>(fsbuff.FS_BLKSZ);
290 return static_cast<long long>(fsbuff.f_bavail)
291 *
static_cast<long long>(fsbuff.FS_BLKSZ);
311 if (!path || FS_Stat(path, &fsbuff))
return -1;
313 Space.
Total =
static_cast<long long>(fsbuff.f_blocks)
314 *
static_cast<long long>(fsbuff.FS_BLKSZ);
315 Space.
Free =
static_cast<long long>(fsbuff.f_bavail)
316 *
static_cast<long long>(fsbuff.FS_BLKSZ);
317 Space.
Inodes=
static_cast<long long>(fsbuff.f_files);
318 Space.
Inleft=
static_cast<long long>(fsbuff.FS_FFREE);
334 while(fsg && strcmp(sname, fsg->
group)) fsg = fsg->
next;
339 return getSpace(Space, fsg, vsPart);
370 for (
int i = 0; i < fsg->
fsNum; i++)
405 while(fsdp && fsdp->
fsid != devid) fsdp = fsdp->
next;
411 {
DEBUG(
"free=" <<fsdp->
frsz <<
'-' <<size <<
" path=" <<fsdp->
path);
412 if ((fsdp->
frsz -= size) < 0) fsdp->
frsz = 0;
415 DEBUG(
"dev " <<devid <<
" not found.");
443 {
if ((buf->st_mode & S_IFMT) != S_IFLNK) Adjust(buf->st_dev, size);
444 else {
char lnkbuff[MAXPATHLEN+64];
445 int lnklen = readlink(
Path, lnkbuff,
sizeof(lnkbuff)-1);
448 Adjust(lnkbuff, size);
457 while(fsp && strcmp(fsp->
path,
Path))
458 if ((fsp = fsp->
next) == fsfirst) {fsp = 0;
break;}
462 if (fsp) Adjust(fsp, size);
463 else {
DEBUG(
"cache path " <<
Path <<
" not found.");}
478 DEBUG(
"free=" <<fsdp->
frsz <<
'-' <<size <<
" path=" <<fsdp->
path);
481 if ( (fsdp->
frsz -= size) < 0) fsdp->
frsz = 0;
495 static const mode_t theMode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
501 long long size, maxfree, curfree;
502 int rc, madeDir, datfd = 0;
507 || (size=aInfo.
cgSize*ovhAlloc/100+aInfo.
cgSize) < minAlloc)
508 aInfo.
cgSize = size = minAlloc;
514 if (!cgp)
return -ENOENT;
520 fsp_sel = 0; maxfree = 0;
521 fsp = cgp->
curr->
next; fspend = fsp;
527 if (size > curfree)
continue;
529 if (fuzAlloc > 0.999) {fsp_sel = fsp;
break;}
530 else if (!fuzAlloc || !fsp_sel)
531 {
if (curfree > maxfree) {fsp_sel = fsp; maxfree = curfree;}}
532 else {diffree = (!(curfree + maxfree) ? 0.0
533 :
static_cast<double>(
XRDABS(maxfree - curfree)) /
534 static_cast<double>( maxfree + curfree));
535 if (diffree > fuzAlloc) {fsp_sel = fsp; maxfree = curfree;}
537 }
while((fsp = fsp->
next) != fspend);
541 if (!fsp_sel)
return -ENOSPC;
554 if (!(*aInfo.
cgPFbf))
return -ENAMETOOLONG;
560 do {
do {datfd =
open(aInfo.
cgPFbf,O_CREAT|O_TRUNC|O_WRONLY,aInfo.
aMode);}
561 while(datfd < 0 && errno == EINTR);
562 if (datfd >= 0 || errno != ENOENT || madeDir)
break;
566 if (datfd < 0)
return (errno ? -errno : -EFAULT);
575 aInfo.
cgFSp = fsp_sel;
589 {memset(&buf, 0,
sizeof(
struct stat));
597 std::map<dev_t, devID>::iterator it =
dev2ID.find(buf.st_dev);
599 {buf.st_rdev =
static_cast<dev_t
>(it->second.bdevID);
600 buf.st_dev =
static_cast<dev_t
>(it->second.partID);
614 char lnkbuff[MAXPATHLEN+64];
620 {
if (
strlcpy(lnkbuff,
Path,
sizeof(lnkbuff)) >=
sizeof(lnkbuff))
return 0;}
622 || (sfbuff.st_mode & S_IFMT) != S_IFLNK
623 || (lnklen = readlink(
Path,lnkbuff,
sizeof(lnkbuff)-1)) <= 0)
633 while(fsp && strcmp(fsp->
path, lnkbuff))
634 if ((fsp = fsp->
next) == fsfirst) {fsp = 0;
break;}
653 if (Qfile) Quotas = !isSOL;
654 if (UPath)
Usage = 1;
660 do {cgp->
GRPid = XrdOssSpace::Assign(cgp->
group, bytesUsed);
661 cgp->
Usage = bytesUsed;
662 }
while((cgp = cgp->
next));
674 fuzAlloc =
static_cast<double>(aFuzz)/100.0;
685 const char *theCmd, *rpath;
686 char *pP, buff[4096];
688 if ((fsp = fsfirst))
do
690 {pP = (
char *)fsp->
path + fsp->
plen - 1;
691 do {pP--;}
while(*pP !=
'/');
692 *pP =
'\0'; theCmd =
"space";
693 }
else {pP=0; theCmd =
"cache";}
696 snprintf(buff,
sizeof(buff),
"%s%s %s %s -> %s[%d:%d] %s",
702 }
while(fsp != fsfirst);
712 const char *pPart =
"/proc/partitions";
713 std::map<std::string, int> dn2id;
716 char *line, *sMaj, *sMin, *sBlk, *sDev, sAlt[16], sDN[
sizeof(devID::nDev)];
718 int dNum, n, fd, vMaj, vMin;
723 if ((fd =
open(pPart, O_RDONLY)) < 0)
return;
729 {
if (!(sMaj = strm.
GetToken()) || !isdigit(*sMaj))
continue;
730 if (!(vMaj = atoi(sMaj)))
continue;
731 if (!(sMin = strm.
GetToken()) || !isdigit(*sMin))
continue;
733 if (!(sBlk = strm.
GetToken()) || !isdigit(*sBlk))
continue;
734 if (!(sDev = strm.
GetToken()))
continue;
738 if (!strncmp(sDev,
"dm-", 3))
739 {
if (!MapDM(sDev, sAlt,
sizeof(sAlt)))
740 {
if (dBug) std::cerr <<
"Config " <<sDev <<
'[' <<vMaj <<
':'
741 <<vMin <<
"] -> dev[0]" <<std::endl;
750 if (sDev[1] !=
'd' || (*sDev !=
's' && *sDev !=
'h'))
continue;
751 strlcpy(sDN, sDev,
sizeof(sDN));
752 sDN[
sizeof(sDN)-1] = 0;
757 while(isdigit(sDev[n])) sDev[n--] = 0;
761 std::map<std::string,int>::iterator it = dn2id.find(std::string(sDev));
762 if (it != dn2id.end()) dNum = it->second;
764 dn2id[std::string(sDev)] = dNum;
769 dNode = makedev(vMaj, vMin);
770 devID theID = {dNum, 0, {0}};
771 strcpy(theID.
nDev, sDN);
776 if (dBug) std::cerr <<
"Config " <<sOrg <<
'[' <<vMaj <<
':' <<vMin
777 <<
"] -> " <<sDev <<
'[' <<dNum <<
']' <<std::endl;
786 bool XrdOssCache::MapDM(
const char *ldm,
char *buff,
int blen)
788 const char *dmInfo1 =
"/sys/devices/virtual/block/", *dmInfo2 =
"/slaves";
792 std::string dmPath = dmInfo1;
796 DIR *slaves =
opendir(dmPath.c_str());
797 if (!slaves)
return 0;
799 {
if (dP->d_type == DT_LNK && dP->d_name[1] ==
'd'
800 && (dP->d_name[0] ==
's' || dP->d_name[0] ==
'h'))
801 {
if ((
int)strlen(dP->d_name) < blen)
802 {strcpy(buff, dP->d_name); aOK =
true;
break;}
820 if (!token || *token ==
':')
827 if (!(
Path = (
char *) index(token,
':')))
strlcpy(cbuff, token, cblen);
828 else {
int n =
Path - token;
829 if (n >= cblen) n = cblen-1;
830 strncpy(cbuff, token, n); cbuff[n] =
'\0';
848 const struct timespec naptime = {cscanint, 0};
850 int retc, dbgMsg, dbgNoMsg, dbgDoMsg;
854 if (cscanint > 60) dbgMsg = cscanint/60;
861 {
if (cscanint > 0) nanosleep(&naptime, 0);
862 dbgDoMsg = !dbgNoMsg--;
863 if (dbgDoMsg) dbgNoMsg = dbgMsg;
882 "state file system ",(
char *)fsdp->
path);
883 else {fsdp->
frsz = frsz;
901 if (cscanint <= 0)
return (
void *)0;
905 if (
Usage && XrdOssSpace::Readjust())
void Usage(const char *msg)
#define XrdOssFSData_REFRESH
#define XrdOssFSData_ADJUSTED
#define OSS_CGROUP_DEFAULT
int stat(const char *path, struct stat *buf)
struct dirent * readdir(DIR *dirp)
int open(const char *path, int oflag,...)
int lstat(const char *path, struct stat *buf)
int mkdir(const char *path, mode_t mode)
DIR * opendir(const char *path)
XrdOssCache_FSData(const char *, STATFS_t &, dev_t)
XrdOssCache_FSData * next
static int getSpace(XrdOssCache_Space &Space, const char *sname, XrdOssVSPart **vsPart=0)
XrdOssCache_Group * fsgroup
static long long freeSpace(long long &Size, const char *path=0)
static int Add(const char *Path)
XrdOssCache_FSData * fsdata
XrdOssCache_FS(int &retc, const char *fsg, const char *fsp, FSOpts opt)
static long long PubQuota
static XrdOssCache_Group * fsgroups
static XrdOssCache_Group * PubGroup
static int Init(const char *UDir, const char *Qfile, int isSOL, int usync=0)
static XrdOssCache_FSData * fsdata
static void * Scan(int cscanint)
static int Alloc(allocInfo &aInfo)
static void DevInfo(struct stat &buf, bool limits=false)
static char * Parse(const char *token, char *cbuff, int cblen)
static XrdOssCache_FS * fsfirst
static void List(const char *lname, XrdSysError &Eroute)
static XrdOssCache_FS * fslast
static void MapDevs(bool dBug=false)
static XrdOssCache_FS * Find(const char *Path, int lklen=0)
static void Adjust(dev_t devid, off_t size)
static char * genPFN(fnInfo &Info, char *buff, int blen, const char *Path=0)
static void Trim2Base(char *eP)
static char * genPath(const char *inPath, const char *cgrp, char *sfx)
static long long Usage(int gent)
static void Adjust(int Gent, off_t Space, sType=Serv)
int Attach(int FileDescriptor, int bsz=2047)
char * GetToken(int lowcase=0)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
std::map< dev_t, devID > dev2ID