00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 const char *XrdOssSpaceCVSID = "$Id: XrdOssSpace.cc 35287 2010-09-14 21:19:35Z ganis $";
00014
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #include <fcntl.h>
00018 #include <errno.h>
00019 #include <stddef.h>
00020 #include <stdio.h>
00021
00022 #include "XrdOss/XrdOssCache.hh"
00023 #include "XrdOss/XrdOssSpace.hh"
00024 #include "XrdOuc/XrdOuca2x.hh"
00025 #include "XrdOuc/XrdOucEnv.hh"
00026 #include "XrdOuc/XrdOucStream.hh"
00027 #include "XrdOuc/XrdOucUtils.hh"
00028 #include "XrdSys/XrdSysError.hh"
00029 #include "XrdSys/XrdSysPlatform.hh"
00030
00031
00032
00033
00034
00035 extern XrdSysError OssEroute;
00036
00037 const char *XrdOssSpace::qFname = 0;
00038 const char *XrdOssSpace::uFname = 0;
00039 XrdOssSpace::uEnt XrdOssSpace::uData[XrdOssSpace::maxEnt] = {{{0}}};
00040 short XrdOssSpace::uDvec[XrdOssSpace::maxEnt] = {0};
00041 int XrdOssSpace::fencEnt = 0;
00042 int XrdOssSpace::freeEnt =-1;
00043 int XrdOssSpace::aFD =-1;
00044 int XrdOssSpace::Solitary = 0;
00045 time_t XrdOssSpace::lastMtime = 0;
00046
00047
00048
00049
00050
00051 void XrdOssSpace::Adjust(int Gent, off_t Space, sType stNum)
00052 {
00053 int offset, unlk = 0;
00054 int uOff = offsetof(uEnt,Bytes[0]) + (sizeof(long long)*stNum);
00055
00056
00057
00058 if (Gent < 0 || Gent >= fencEnt) return;
00059 offset = sizeof(uEnt)*Gent + uOff;
00060
00061
00062
00063
00064 if (Solitary && stNum == Serv) stNum = (Space > 0 ? Pstg : Purg);
00065
00066
00067
00068
00069 if (stNum != Serv)
00070 {if (!UsageLock()) return;
00071 if (pread(aFD, &uData[Gent], sizeof(uEnt), offset-uOff) < 0)
00072 {OssEroute.Emsg("Adjust", errno, "read usage file", uFname);
00073 UsageLock(0); return;
00074 }
00075 if (stNum == Admin)
00076 {uData[Gent].Bytes[Admin] = 0;
00077 Space = Space - uData[Gent].Bytes[Pstg] + uData[Gent].Bytes[Purg];
00078 }
00079 unlk = 1;
00080 }
00081
00082
00083
00084 if ((uData[Gent].Bytes[stNum] += Space) < 0 && stNum != Admin)
00085 uData[Gent].Bytes[stNum] = 0;
00086
00087
00088
00089
00090 if (pwrite(aFD, &uData[Gent].Bytes[stNum], ULen, offset) < 0)
00091 OssEroute.Emsg("Adjust", errno, "update usage file", uFname);
00092
00093
00094
00095 if (unlk) UsageLock(0);
00096 }
00097
00098
00099
00100 void XrdOssSpace::Adjust(const char *GName, off_t Space, sType stNum)
00101 {
00102 int i;
00103
00104
00105
00106 if ((i = findEnt(GName)) >= 0) Adjust(i, Space, stNum);
00107 }
00108
00109
00110
00111
00112
00113 int XrdOssSpace::Assign(const char *GName, long long &Usage)
00114 {
00115 off_t offset;
00116 int i;
00117
00118
00119
00120 if ((i = findEnt(GName)) >= 0)
00121 {Usage = uData[i].Bytes[Serv];
00122 return i;
00123 }
00124
00125
00126
00127 Usage = 0;
00128 if (freeEnt >= maxEnt || freeEnt < 0)
00129 {OssEroute.Emsg("Assign", uFname, "overflowed for", GName);
00130 return -1;
00131 }
00132
00133
00134
00135 if (!UsageLock()) return -1;
00136 memset(&uData[freeEnt], 0, sizeof(uEnt));
00137 strcpy(uData[freeEnt].gName, GName);
00138 uData[freeEnt].Bytes[addT] = static_cast<long long>(time(0));
00139 offset = sizeof(uEnt) * freeEnt;
00140 if (pwrite(aFD, &uData[freeEnt], sizeof(uEnt), offset) < 0)
00141 {OssEroute.Emsg("Adjust", errno, "update usage file", uFname);
00142 UsageLock(0); return -1;
00143 }
00144 UsageLock(0);
00145
00146
00147
00148 uDvec[fencEnt++] = i = freeEnt;
00149
00150
00151
00152 for (freeEnt = freeEnt+1; freeEnt < maxEnt; freeEnt++)
00153 if (*uData[freeEnt].gName == '\0') break;
00154
00155
00156
00157 return i;
00158 }
00159
00160
00161
00162
00163
00164 int XrdOssSpace::findEnt(const char *GName)
00165 {
00166 int i;
00167
00168
00169
00170 for (i = 0; i < fencEnt; i++)
00171 if (!strcmp(uData[uDvec[i]].gName, GName)) return i;
00172 return -1;
00173 }
00174
00175
00176
00177
00178
00179 int XrdOssSpace::Init() {return (uFname ? haveUsage:0) | (qFname ? haveQuota:0);}
00180
00181
00182
00183 int XrdOssSpace::Init(const char *aPath, const char *qPath, int isSOL)
00184 {
00185 static const mode_t theMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
00186 struct stat buf;
00187 const char *iP;
00188 char *aP, buff[1048];
00189 int i, opts, updt = 0;
00190
00191
00192
00193 Solitary = isSOL;
00194
00195
00196
00197 if (qPath)
00198 {qFname = strdup(qPath);
00199 if (!Quotas()) return 0;
00200 XrdOucEnv::Export("XRDOSSQUOTAFILE", qFname);
00201 }
00202
00203
00204
00205 if (!aPath) return 1;
00206 strcpy(buff, aPath);
00207 aP = buff + strlen(aPath);
00208 if (*(aP-1) != '/') *aP++ = '/';
00209 if ((iP = XrdOucUtils::InstName(-1)))
00210 {strcpy(aP, iP); aP += strlen(iP); *aP++ = '/'; *aP = '\0';
00211 mkdir(buff, S_IRWXU | S_IRWXG);
00212 }
00213 strcpy(aP, ".Usage");
00214 uFname = strdup(buff);
00215 XrdOucEnv::Export("XRDOSSUSAGEFILE", uFname);
00216
00217
00218
00219 if (stat(uFname, &buf))
00220 if (errno != ENOENT)
00221 {OssEroute.Emsg("Init", errno, "open", uFname);
00222 return 0;
00223 } else opts = O_CREAT|O_TRUNC;
00224 else if ( buf.st_size != DataSz && buf.st_size)
00225 {OssEroute.Emsg("Init", uFname, "has invalid size."); return 0;}
00226 else opts = 0;
00227
00228
00229
00230 if ((aFD = open(uFname, opts|O_RDWR|O_SYNC, theMode)) < 0)
00231 {OssEroute.Emsg("Init", errno, "open", uFname);
00232 return 0;
00233 }
00234
00235
00236
00237 UsageLock();
00238
00239
00240
00241 if (opts & O_CREAT || buf.st_size == 0)
00242 {memset(uData, 0, sizeof(uData));
00243 if (!write(aFD, uData, sizeof(uData)))
00244 {OssEroute.Emsg("Init", errno, "create", uFname);
00245 UsageLock(0); return 0;
00246 }
00247 fencEnt = 0; freeEnt = 0;
00248 } else {
00249 if (!read(aFD, uData, sizeof(uData)))
00250 {OssEroute.Emsg("Init", errno, "read", uFname);
00251 UsageLock(0); return 0;
00252 }
00253 for (i = 0; i < maxEnt; i++)
00254 {if (*uData[i].gName != '\0')
00255 {uDvec[fencEnt++] = i; updt = Readjust(i);}
00256 else if (freeEnt < 0) freeEnt = i;
00257 }
00258 if (freeEnt < 0) OssEroute.Emsg("Init", uFname, "is full.");
00259 }
00260
00261
00262
00263 if (updt && pwrite(aFD, uData, sizeof(uData), 0) < 0)
00264 OssEroute.Emsg("Init", errno, "rewrite", uFname);
00265
00266
00267
00268 UsageLock(0);
00269 sprintf(buff, "%d usage log entries in use; %d available.",
00270 fencEnt, maxEnt-fencEnt);
00271 OssEroute.Emsg("Init", buff);
00272 return 1;
00273 }
00274
00275
00276
00277
00278
00279 int XrdOssSpace::Quotas()
00280 {
00281 XrdOucStream Config(&OssEroute);
00282 XrdOssCache_Group *fsg;
00283 struct stat buf;
00284 long long qval;
00285 char cgroup[minSNbsz], *val;
00286 int qFD, NoGo = 0;
00287
00288
00289
00290 if (stat(qFname,&buf))
00291 {OssEroute.Emsg("Quotas", errno, "process quota file", qFname);
00292 return 0;
00293 }
00294 if (buf.st_mtime == lastMtime) return 0;
00295 lastMtime = buf.st_mtime;
00296
00297
00298
00299 if ( (qFD = open(qFname, O_RDONLY, 0)) < 0)
00300 {OssEroute.Emsg("Quotas", errno, "open quota file", qFname);
00301 return 0;
00302 }
00303
00304
00305
00306 OssEroute.Emsg("Quotas", "Processing quota file", qFname);
00307 Config.Attach(qFD);
00308
00309
00310
00311 while((val = Config.GetMyFirstWord()))
00312 {if (strlen(val) >= sizeof(cgroup))
00313 {OssEroute.Emsg("Quotas", "invalid quota group =", val);
00314 NoGo = 1; continue;
00315 }
00316 strcpy(cgroup, val);
00317
00318 if (!(val = Config.GetWord()))
00319 {OssEroute.Emsg("Quotas", "quota value not specified for", cgroup);
00320 NoGo = 1; continue;
00321 }
00322 if (XrdOuca2x::a2sz(OssEroute, "quota", val, &qval))
00323 {NoGo = 1; continue;
00324 }
00325 fsg = XrdOssCache_Group::fsgroups;
00326 while(fsg && strcmp(cgroup, fsg->group)) fsg = fsg->next;
00327 if (fsg) fsg->Quota = qval;
00328 if (!strcmp("public", cgroup)) XrdOssCache_Group::PubQuota = qval;
00329 else if (!fsg) OssEroute.Emsg("Quotas", cgroup,
00330 "cache group not found; quota ignored");
00331 }
00332 close(qFD);
00333 return (NoGo ? 0 : 1);
00334 }
00335
00336
00337
00338
00339
00340 int XrdOssSpace::Readjust()
00341 {
00342 static time_t lastUtime = 0;
00343 struct stat buf;
00344 int k, rwsz, updt = 0;
00345
00346
00347
00348 if (fencEnt <= 0) return 0;
00349 if (!fstat(aFD, &buf))
00350 {if (buf.st_mtime == lastUtime) return 0;
00351 lastUtime = buf.st_mtime;
00352 }
00353 rwsz = sizeof(uEnt)*(uDvec[fencEnt-1] + 1);
00354
00355
00356
00357 UsageLock();
00358
00359
00360
00361 if (!pread(aFD, uData, rwsz, 0))
00362 {OssEroute.Emsg("Readjust", errno, "read", uFname);
00363 UsageLock(0); return 0;
00364 }
00365
00366
00367
00368 for (k = 0; k < fencEnt; k++) updt |= Readjust(uDvec[k]);
00369
00370
00371
00372 if (updt && pwrite(aFD, uData, rwsz, 0) < 0)
00373 OssEroute.Emsg("Readjust", errno, "rewrite", uFname);
00374
00375
00376
00377 UsageLock(0);
00378 return updt;
00379 }
00380
00381
00382
00383 int XrdOssSpace::Readjust(int i)
00384 {
00385
00386
00387
00388 if (uData[i].Bytes[Pstg] || uData[i].Bytes[Purg] || uData[i].Bytes[Admin])
00389 {uData[i].Bytes[Serv] = uData[i].Bytes[Serv] + uData[i].Bytes[Pstg]
00390 - uData[i].Bytes[Purg] + uData[i].Bytes[Admin];
00391 uData[i].Bytes[Pstg] = uData[i].Bytes[Purg] = uData[i].Bytes[Admin] = 0;
00392 return 1;
00393 }
00394 return 0;
00395 }
00396
00397
00398
00399
00400
00401 int XrdOssSpace::Unassign(const char *GName)
00402 {
00403 off_t offset;
00404 int k, i;
00405
00406
00407
00408 for (k = 0; k < fencEnt; k++)
00409 if (!strcmp(uData[uDvec[k]].gName, GName)) break;
00410 if (k >= fencEnt) return -1;
00411 i = uDvec[k];
00412
00413
00414
00415 if (!UsageLock()) return -1;
00416 memset(&uData[i], 0, sizeof(uEnt));
00417 offset = sizeof(uEnt) * i;
00418 if (pwrite(aFD, &uData[freeEnt], sizeof(uEnt), offset) < 0)
00419 {OssEroute.Emsg("Unassign", errno, "update usage file", uFname);
00420 UsageLock(0); return -1;
00421 }
00422 UsageLock(0);
00423
00424
00425
00426 if (i < freeEnt) freeEnt = i;
00427 for (i = k+1; i < fencEnt; i++) uDvec[k++] = uDvec[i];
00428 fencEnt--;
00429 return 0;
00430 }
00431
00432
00433
00434
00435
00436 long long XrdOssSpace::Usage(const char *GName, struct uEnt &uVal, int rrd)
00437 {
00438 int i, rwsz;
00439
00440
00441
00442 if (rrd)
00443 {if (fencEnt <= 0) return -1;
00444 UsageLock();
00445 rwsz = sizeof(uEnt)*(uDvec[fencEnt-1] + 1);
00446 if (!pread(aFD, uData, rwsz, 0))
00447 {OssEroute.Emsg("Readjust", errno, "read", uFname);
00448 UsageLock(0); return -1;
00449 }
00450 UsageLock(0);
00451 }
00452
00453
00454
00455 if ((i = findEnt(GName)) >= 0)
00456 {uVal = uData[i];
00457 return uData[i].Bytes[Serv];
00458 }
00459
00460
00461
00462 memset(&uVal, 0, sizeof(uEnt));
00463 return -1;
00464 }
00465
00466
00467
00468
00469
00470 int XrdOssSpace::UsageLock(int Dolock)
00471 {
00472 FLOCK_t lock_args;
00473 const char *What;
00474 int rc;
00475
00476
00477
00478 bzero(&lock_args, sizeof(lock_args));
00479 if (Dolock) {lock_args.l_type = F_WRLCK; What = "lock";}
00480 else {lock_args.l_type = F_UNLCK; What = "unlock";}
00481
00482
00483
00484 do {rc = fcntl(aFD,F_SETLKW,&lock_args);} while(rc < 0 && errno == EINTR);
00485 if (rc < 0) {OssEroute.Emsg("UpdateLock", errno, What, uFname); return 0;}
00486
00487
00488
00489 return 1;
00490 }