XRootD
Loading...
Searching...
No Matches
XrdOssCsi.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d O s s C s i . c c */
4/* */
5/* (C) Copyright 2020 CERN. */
6/* */
7/* This file is part of the XRootD software suite. */
8/* */
9/* XRootD is free software: you can redistribute it and/or modify it under */
10/* the terms of the GNU Lesser General Public License as published by the */
11/* Free Software Foundation, either version 3 of the License, or (at your */
12/* option) any later version. */
13/* */
14/* In applying this licence, CERN does not waive the privileges and */
15/* immunities granted to it by virtue of its status as an Intergovernmental */
16/* Organization or submit itself to any jurisdiction. */
17/* */
18/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
19/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
20/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
21/* License for more details. */
22/* */
23/* You should have received a copy of the GNU Lesser General Public License */
24/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
25/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
26/* */
27/* The copyright holder's institutional names and contributor's names may not */
28/* be used to endorse or promote products derived from this software without */
29/* specific prior written permission of the institution or contributor. */
30/******************************************************************************/
31
32#include "XrdOssCsiTrace.hh"
33#include "XrdOssCsi.hh"
34#include "XrdOssCsiConfig.hh"
35#include "XrdOuc/XrdOucEnv.hh"
37#include "XrdOuc/XrdOuca2x.hh"
38#include "XrdVersion.hh"
39
40#include <string>
41#include <memory>
42
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <fcntl.h>
46#include <limits.h>
47#include <assert.h>
48
50
53
54XrdScheduler *XrdOssCsi::Sched_;
55
56int XrdOssCsiDir::Opendir(const char *path, XrdOucEnv &env)
57{
58 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
59
60 skipsuffix_ = !config_.tagParam_.hasPrefix();
61 if (!skipsuffix_)
62 {
63 skipprefix_ = config_.tagParam_.matchPrefixDir(path);
64 if (skipprefix_)
65 {
66 skipprefixname_ = config_.tagParam_.getPrefixName();
67 }
68 }
69 return successor_->Opendir(path, env);
70}
71
72// skip tag files in directory listing
73int XrdOssCsiDir::Readdir(char *buff, int blen)
74{
75 int ret;
76 do
77 {
78 ret = successor_->Readdir(buff, blen);
79 if (ret<0) return ret;
80 if (skipsuffix_)
81 {
82 if (config_.tagParam_.isTagFile(buff)) continue;
83 }
84 else if (skipprefix_)
85 {
86 if (skipprefixname_ == buff) continue;
87 }
88 break;
89 } while(1);
90 return ret;
91}
92
94{
95 // tident starting with '*' is a special case to bypass OssCsi
96 if (tident && *tident == '*')
97 {
98 return successor_->newDir(tident);
99 }
100
101 return (XrdOssDF *)new XrdOssCsiDir(successor_, tident, config_);
102}
103
105{
106 // tident starting with '*' is a special case to bypass OssCsi
107 if (tident && *tident == '*')
108 {
109 return successor_->newFile(tident);
110 }
111
112 return (XrdOssDF *)new XrdOssCsiFile(successor_, tident, config_);
113}
114
115int XrdOssCsi::Init(XrdSysLogger *lP, const char *cP, const char *params, XrdOucEnv *env)
116{
117 OssCsiEroute.logger(lP);
118
119 int cret = config_.Init(OssCsiEroute, cP, params, env);
120 if (cret != XrdOssOK)
121 {
122 return cret;
123 }
124
125 if ( ! env ||
126 ! (Sched_ = (XrdScheduler*) env->GetPtr("XrdScheduler*")))
127 {
128 Sched_ = new XrdScheduler;
129 Sched_->Start();
130 }
131
132 return XrdOssOK;
133}
134
135int XrdOssCsi::Unlink(const char *path, int Opts, XrdOucEnv *eP)
136{
137 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
138
139 // get mapinfo entries for file
140 std::shared_ptr<XrdOssCsiFile::puMapItem_t> pmi;
141 {
142 const std::string tpath = config_.tagParam_.makeTagFilename(path);
143 XrdOssCsiFile::mapTake(tpath, pmi);
144 }
145
146 int utret = 0;
147
148 XrdSysMutexHelper lck(pmi->mtx);
149 pmi->dpath = path;
150 if (!pmi->unlinked)
151 {
152 const int uret = successor_->Unlink(path, Opts, eP);
153 if (uret != XrdOssOK)
154 {
156 return uret;
157 }
158
159 utret = successor_->Unlink(pmi->tpath.c_str(), Opts, eP);
160 }
161
162 pmi->unlinked = true;
164
165 return (utret == -ENOENT) ? 0 : utret;
166}
167
168int XrdOssCsi::Rename(const char *oldname, const char *newname,
169 XrdOucEnv *old_env, XrdOucEnv *new_env)
170{
171 if (config_.tagParam_.isTagFile(oldname) || config_.tagParam_.isTagFile(newname)) return -ENOENT;
172
173 const std::string inew = config_.tagParam_.makeTagFilename(newname);
174 const std::string iold = config_.tagParam_.makeTagFilename(oldname);
175
176 // get mapinfo entries for both old and possibly existing newfile
177 std::shared_ptr<XrdOssCsiFile::puMapItem_t> newpmi,pmi;
178 XrdOssCsiFile::mapTake(inew, newpmi);
179 XrdOssCsiFile::mapTake(iold , pmi);
180
181 // rename to self, do nothing
182 if (newpmi == pmi)
183 {
186 return 0;
187 }
188
189 // take in consistent order
190 XrdSysMutexHelper lck(NULL), lck2(NULL);
191 if (newpmi > pmi)
192 {
193 lck.Lock(&newpmi->mtx);
194 lck2.Lock(&pmi->mtx);
195 }
196 else
197 {
198 lck2.Lock(&pmi->mtx);
199 lck.Lock(&newpmi->mtx);
200 }
201
202 if (pmi->unlinked || newpmi->unlinked)
203 {
204 // something overwrote the source or target file since we checked
205 XrdOssCsiFile::mapRelease(pmi,&lck2);
206 XrdOssCsiFile::mapRelease(newpmi,&lck);
207 return Rename(oldname, newname, old_env, new_env);
208 }
209
210 const int sret = successor_->Rename(oldname, newname, old_env, new_env);
211 if (sret<0)
212 {
213 XrdOssCsiFile::mapRelease(pmi,&lck2);
214 XrdOssCsiFile::mapRelease(newpmi,&lck);
215 return sret;
216 }
217
218 int mkdret = XrdOssOK;
219 {
220 std::string base = inew;
221 const size_t idx = base.rfind("/");
222 base = base.substr(0,idx);
223 if (!base.empty())
224 {
225 const int AMode = S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH; // 775
226 mkdret = successor_->Mkdir(base.c_str(), AMode, 1, new_env);
227 }
228 }
229
230 if (mkdret != XrdOssOK && mkdret != -EEXIST)
231 {
232 (void) successor_->Rename(newname, oldname, new_env, old_env);
233 XrdOssCsiFile::mapRelease(pmi,&lck2);
234 XrdOssCsiFile::mapRelease(newpmi,&lck);
235 return mkdret;
236 }
237
238 const int iret = successor_->Rename(iold.c_str(), inew.c_str(), old_env, new_env);
239 if (iret<0)
240 {
241 if (iret == -ENOENT)
242 {
243 // old tag did not exist, make sure there is no new tag
244 (void) successor_->Unlink(inew.c_str(), 0, new_env);
245 }
246 else
247 {
248 (void) successor_->Rename(newname, oldname, new_env, old_env);
249 XrdOssCsiFile::mapRelease(pmi,&lck2);
250 XrdOssCsiFile::mapRelease(newpmi,&lck);
251 return iret;
252 }
253 }
254
255 if (newpmi)
256 {
257 newpmi->unlinked = true;
258 }
259
260 {
262 auto mapidx_new = XrdOssCsiFile::pumap_.find(inew);
263 if (mapidx_new != XrdOssCsiFile::pumap_.end()) XrdOssCsiFile::pumap_.erase(mapidx_new);
264
265 auto mapidx = XrdOssCsiFile::pumap_.find(iold);
266 assert(mapidx != XrdOssCsiFile::pumap_.end());
267
268 XrdOssCsiFile::pumap_.erase(mapidx);
269 XrdOssCsiFile::pumap_.insert(std::make_pair(inew, pmi));
270 pmi->dpath = newname;
271 pmi->tpath = inew;
272 }
273
274 XrdOssCsiFile::mapRelease(pmi,&lck2);
275 XrdOssCsiFile::mapRelease(newpmi,&lck);
276
277 return XrdOssOK;
278}
279
280int XrdOssCsi::Truncate(const char *path, unsigned long long size, XrdOucEnv *envP)
281{
282 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
283
284 std::unique_ptr<XrdOssDF> fp(newFile("xrdt"));
285 XrdOucEnv myEnv;
286 int ret = fp->Open(path, O_RDWR, 0, envP ? *envP : myEnv);
287 if (ret != XrdOssOK)
288 {
289 return ret;
290 }
291 ret = fp->Ftruncate(size);
292 if (ret != XrdOssOK)
293 {
294 return ret;
295 }
296 long long retsz=0;
297 fp->Close(&retsz);
298 return XrdOssOK;
299}
300
301int XrdOssCsi::Reloc(const char *tident, const char *path,
302 const char *cgName, const char *anchor)
303{
304 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
305 return successor_->Reloc(tident, path, cgName, anchor);
306}
307
308int XrdOssCsi::Mkdir(const char *path, mode_t mode, int mkpath, XrdOucEnv *envP)
309{
310 if (config_.tagParam_.isTagFile(path)) return -EACCES;
311 return successor_->Mkdir(path, mode, mkpath, envP);
312}
313
314int XrdOssCsi::Create(const char *tident, const char *path, mode_t access_mode,
315 XrdOucEnv &env, int Opts)
316{
317 // tident starting with '*' is a special case to bypass OssCsi
318 if (tident && *tident == '*')
319 {
320 return successor_->Create(tident, path, access_mode, env, Opts);
321 }
322
323 if (config_.tagParam_.isTagFile(path)) return -EACCES;
324
325 // get mapinfo entries for file
326 std::shared_ptr<XrdOssCsiFile::puMapItem_t> pmi;
327 {
328 const std::string tpath = config_.tagParam_.makeTagFilename(path);
329 XrdOssCsiFile::mapTake(tpath, pmi);
330 }
331
332 XrdSysMutexHelper lck(pmi->mtx);
333 if (pmi->unlinked)
334 {
336 return Create(tident, path, access_mode, env, Opts);
337 }
338
339 const bool isTrunc = ((Opts>>8)&O_TRUNC) ? true : false;
340 const bool isExcl = ((Opts&XRDOSS_new) || ((Opts>>8)&O_EXCL)) ? true : false;
341
342 if (isTrunc && pmi->pages)
343 {
344 // truncate of already open file at open() not supported
345 XrdOssCsiFile::mapRelease(pmi, &lck);
346 return -EDEADLK;
347 }
348
349 // create file: require it not to exist (unless we're truncating) so that
350 // we can tell if we have a zero length file without stat in more cases
351
352 const int exflags = isTrunc ? 0 : ((O_EXCL<<8)|XRDOSS_new);
353
354 int ret = successor_->Create(tident, path, access_mode, env, Opts | exflags);
355 if (ret == XrdOssOK || ret == -EEXIST)
356 {
357 // success from trunc/exclusive create means the file must now be zero length
358 bool zlen = (ret == XrdOssOK) ? true : false;
359 struct stat sbuf;
360 if (!zlen && successor_->Stat(path, &sbuf, 0, &env) == XrdOssOK)
361 {
362 // had to check file size
363 if (sbuf.st_size == 0)
364 {
365 zlen = true;
366 }
367 }
368
369 // If datafile is zero length try to make empty tag file
370 if (zlen)
371 {
372 const std::string tpath = config_.tagParam_.makeTagFilename(path);
373 const int flags = O_RDWR|O_CREAT|O_TRUNC;
374 const int cropts = XRDOSS_mkpath;
375
376 std::unique_ptr<XrdOucEnv> tagEnv = tagOpenEnv(config_, env);
377
378 ret = successor_->Create(tident, tpath.c_str(), 0666, *tagEnv, (flags<<8)|cropts);
379 }
380 }
381
382 XrdOssCsiFile::mapRelease(pmi, &lck);
383
384 // may not need to return EEXIST
385 return (ret==-EEXIST && !isExcl) ? XrdOssOK : ret;
386}
387
388int XrdOssCsi::Chmod(const char *path, mode_t mode, XrdOucEnv *envP)
389{
390 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
391 return successor_->Chmod(path, mode, envP);
392}
393
394int XrdOssCsi::Remdir(const char *path, int Opts, XrdOucEnv *eP)
395{
396 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
397 const int ret = successor_->Remdir(path, Opts, eP);
398 if (ret != XrdOssOK || !config_.tagParam_.hasPrefix()) return ret;
399
400 // try to remove the corresponding directory under the tagfile directory.
401 // ignore errors
402
403 const std::string tpath = config_.tagParam_.makeBaseDirname(path);
404 (void) successor_->Remdir(tpath.c_str(), Opts, eP);
405 return XrdOssOK;
406}
407
408int XrdOssCsi::Stat(const char *path, struct stat *buff, int opts,
409 XrdOucEnv *EnvP)
410{
411 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
412 return successor_->Stat(path, buff, opts, EnvP);
413}
414
415int XrdOssCsi::StatPF(const char *path, struct stat *buff, int opts)
416{
417 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
418 if (!(opts & XrdOss::PF_dStat)) return successor_->StatPF(path, buff, opts);
419
420 buff->st_rdev = 0;
421 const int pfret = successor_->StatPF(path, buff, opts);
422 if (pfret != XrdOssOK)
423 {
424 return pfret;
425 }
426
427 std::unique_ptr<XrdOssCsiFile> fp((XrdOssCsiFile*)newFile("xrdt"));
428 XrdOucEnv myEnv;
429 const int oret = fp->Open(path, O_RDONLY, 0, myEnv);
430 if (oret != XrdOssOK)
431 {
432 return oret;
433 }
434 const int vs = fp->VerificationStatus();
435
436 long long retsz=0;
437 fp->Close(&retsz);
438
439 buff->st_rdev &= ~(XrdOss::PF_csVer | XrdOss::PF_csVun);
440 buff->st_rdev |= static_cast<dev_t>(vs);
441 return XrdOssOK;
442}
443
444int XrdOssCsi::StatXA(const char *path, char *buff, int &blen,
445 XrdOucEnv *envP)
446{
447 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
448 return successor_->StatXA(path, buff, blen, envP);
449}
450
451
454 const char *config_fn,
455 const char *parms,
456 XrdOucEnv *envP)
457{
458 XrdOssCsi *myOss = new XrdOssCsi(curr_oss);
459 if (myOss->Init(Logger, config_fn, parms, envP) != XrdOssOK)
460 {
461 delete myOss;
462 return NULL;
463 }
464 return (XrdOss*)myOss;
465}
466
467std::unique_ptr<XrdOucEnv> XrdOssCsi::tagOpenEnv(const XrdOssCsiConfig &config, XrdOucEnv &env)
468{
469 // for tagfile open, start with copy of datafile environment
470 int infolen;
471 const char *info = env.Env(infolen);
472 std::unique_ptr<XrdOucEnv> newEnv(new XrdOucEnv(info, infolen, env.secEnv()));
473
474 // give space name for tag files
475 newEnv->Put("oss.cgroup", config.xrdtSpaceName().c_str());
476
477 char *tmp;
478 long long cgSize=0;
479 if ((tmp = env.Get("oss.asize")) && XrdOuca2x::a2sz(OssCsiEroute,"invalid asize",tmp,&cgSize,0))
480 {
481 cgSize=0;
482 }
483
484 if (cgSize>0)
485 {
486 char size_str[32];
487 sprintf(size_str, "%lld", 20+4*((cgSize+XrdSys::PageSize-1)/XrdSys::PageSize));
488 newEnv->Put("oss.asize", size_str);
489 }
490 else
491 {
492 newEnv->Put("oss.asize", "0");
493 }
494
495 return newEnv;
496}
#define tident
static XrdSysLogger Logger
XrdOucTrace OssCsiTrace
XrdOss * XrdOssAddStorageSystem2(XrdOss *curr_oss, XrdSysLogger *Logger, const char *config_fn, const char *parms, XrdOucEnv *envP)
Definition XrdOssCsi.cc:452
XrdVERSIONINFO(XrdOssAddStorageSystem2, XrdOssCsi) XrdSysError OssCsiEroute(0
XrdOucTrace OssCsiTrace & OssCsiEroute
Definition XrdOssCsi.cc:52
osscsi_
Definition XrdOssCsi.cc:51
#define XrdOssOK
Definition XrdOss.hh:50
#define XRDOSS_new
Definition XrdOss.hh:467
#define XRDOSS_mkpath
Definition XrdOss.hh:466
#define stat(a, b)
Definition XrdPosix.hh:101
bool Create
struct myOpts opts
if(ec< 0) ec
std::string makeBaseDirname(const char *path)
std::string makeTagFilename(const char *path)
bool hasPrefix()
bool isTagFile(const char *path)
std::string xrdtSpaceName() const
int Init(XrdSysError &, const char *, const char *, XrdOucEnv *)
virtual int Opendir(const char *path, XrdOucEnv &env)
Definition XrdOssCsi.cc:56
virtual int Readdir(char *buff, int blen)
Definition XrdOssCsi.cc:73
static XrdSysMutex pumtx_
Definition XrdOssCsi.hh:159
static std::unordered_map< std::string, std::shared_ptr< puMapItem_t > > pumap_
Definition XrdOssCsi.hh:160
static void mapTake(const std::string &, std::shared_ptr< puMapItem_t > &, bool create=true)
static int mapRelease(std::shared_ptr< puMapItem_t > &, XrdSysMutexHelper *plck=NULL)
virtual int Remdir(const char *path, int Opts=0, XrdOucEnv *eP=0)
Definition XrdOssCsi.cc:394
virtual int Stat(const char *path, struct stat *buff, int opts=0, XrdOucEnv *EnvP=0)
Definition XrdOssCsi.cc:408
static std::unique_ptr< XrdOucEnv > tagOpenEnv(const XrdOssCsiConfig &, XrdOucEnv &)
Definition XrdOssCsi.cc:467
virtual int Unlink(const char *path, int Opts=0, XrdOucEnv *eP=0)
Definition XrdOssCsi.cc:135
virtual int Reloc(const char *tident, const char *path, const char *cgName, const char *anchor=0)
Definition XrdOssCsi.cc:301
virtual int Init(XrdSysLogger *lp, const char *cfn)
Definition XrdOssCsi.hh:186
virtual XrdOssDF * newFile(const char *tident)
Definition XrdOssCsi.cc:104
virtual int Mkdir(const char *path, mode_t mode, int mkpath=0, XrdOucEnv *envP=0)
Definition XrdOssCsi.cc:308
virtual int Chmod(const char *path, mode_t mode, XrdOucEnv *envP=0)
Definition XrdOssCsi.cc:388
virtual int Create(const char *tident, const char *path, mode_t access_mode, XrdOucEnv &env, int Opts=0)
Definition XrdOssCsi.cc:314
virtual int Truncate(const char *path, unsigned long long size, XrdOucEnv *envP=0)
Definition XrdOssCsi.cc:280
virtual int StatXA(const char *path, char *buff, int &blen, XrdOucEnv *envP=0)
Definition XrdOssCsi.cc:444
static XrdScheduler * Sched_
Definition XrdOssCsi.hh:216
virtual int StatPF(const char *path, struct stat *buff, int opts)
Definition XrdOssCsi.cc:415
virtual int Rename(const char *oldname, const char *newname, XrdOucEnv *old_env=0, XrdOucEnv *new_env=0)
Definition XrdOssCsi.cc:168
virtual XrdOssDF * newDir(const char *tident)
Definition XrdOssCsi.cc:93
XrdOssDF * successor_
virtual int Readdir(char *buff, int blen)
Definition XrdOss.hh:92
XrdOss * successor_
virtual int Mkdir(const char *path, mode_t mode, int mkpath=0, XrdOucEnv *envP=0)=0
static const int PF_dStat
Definition XrdOss.hh:773
virtual int StatXA(const char *path, char *buff, int &blen, XrdOucEnv *envP=0)
Definition XrdOss.cc:127
static const int PF_csVer
verified file checksums present
Definition XrdOss.hh:778
virtual int Create(const char *tid, const char *path, mode_t mode, XrdOucEnv &env, int opts=0)=0
virtual XrdOssDF * newFile(const char *tident)=0
virtual int Reloc(const char *tident, const char *path, const char *cgName, const char *anchor=0)
Definition XrdOss.cc:76
virtual int Chmod(const char *path, mode_t mode, XrdOucEnv *envP=0)=0
virtual int StatPF(const char *path, struct stat *buff, int opts)
Definition XrdOss.cc:107
static const int PF_csVun
unverified file checksums present
Definition XrdOss.hh:779
virtual int Remdir(const char *path, int Opts=0, XrdOucEnv *envP=0)=0
virtual int Rename(const char *oPath, const char *nPath, XrdOucEnv *oEnvP=0, XrdOucEnv *nEnvP=0)=0
virtual XrdOssDF * newDir(const char *tident)=0
virtual int Stat(const char *path, struct stat *buff, int opts=0, XrdOucEnv *envP=0)=0
virtual int Unlink(const char *path, int Opts=0, XrdOucEnv *envP=0)=0
char * Env(int &envlen)
Definition XrdOucEnv.hh:48
const XrdSecEntity * secEnv() const
Definition XrdOucEnv.hh:107
char * Get(const char *varname)
Definition XrdOucEnv.hh:69
void * GetPtr(const char *varname)
Definition XrdOucEnv.cc:263
static int a2sz(XrdSysError &, const char *emsg, const char *item, long long *val, long long minv=-1, long long maxv=-1)
Definition XrdOuca2x.cc:257
void Lock(XrdSysMutex *Mutex)
static const int PageSize