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#include <functional>
43
44#include <sys/types.h>
45#include <sys/stat.h>
46#include <fcntl.h>
47#include <limits.h>
48#include <assert.h>
49
51
54
55XrdScheduler *XrdOssCsi::Sched_;
56
57int XrdOssCsiDir::Opendir(const char *path, XrdOucEnv &env)
58{
59 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
60
61 skipsuffix_ = !config_.tagParam_.hasPrefix();
62 if (!skipsuffix_)
63 {
64 skipprefix_ = config_.tagParam_.matchPrefixDir(path);
65 if (skipprefix_)
66 {
67 skipprefixname_ = config_.tagParam_.getPrefixName();
68 }
69 }
70 return successor_->Opendir(path, env);
71}
72
73// skip tag files in directory listing
74int XrdOssCsiDir::Readdir(char *buff, int blen)
75{
76 int ret;
77 do
78 {
79 ret = successor_->Readdir(buff, blen);
80 if (ret<0) return ret;
81 if (skipsuffix_)
82 {
83 if (config_.tagParam_.isTagFile(buff)) continue;
84 }
85 else if (skipprefix_)
86 {
87 if (skipprefixname_ == buff) continue;
88 }
89 break;
90 } while(1);
91 return ret;
92}
93
95{
96 // tident starting with '*' is a special case to bypass OssCsi
97 if (tident && *tident == '*')
98 {
99 return successor_->newDir(tident);
100 }
101
102 return (XrdOssDF *)new XrdOssCsiDir(successor_, tident, config_);
103}
104
106{
107 // tident starting with '*' is a special case to bypass OssCsi
108 if (tident && *tident == '*')
109 {
110 return successor_->newFile(tident);
111 }
112
113 return (XrdOssDF *)new XrdOssCsiFile(successor_, tident, config_);
114}
115
116int XrdOssCsi::Init(XrdSysLogger *lP, const char *cP, const char *params, XrdOucEnv *env)
117{
118 OssCsiEroute.logger(lP);
119
120 int cret = config_.Init(OssCsiEroute, cP, params, env);
121 if (cret != XrdOssOK)
122 {
123 return cret;
124 }
125
126 if ( ! env ||
127 ! (Sched_ = (XrdScheduler*) env->GetPtr("XrdScheduler*")))
128 {
129 Sched_ = new XrdScheduler;
130 Sched_->Start();
131 }
132
133 return XrdOssOK;
134}
135
136int XrdOssCsi::Unlink(const char *path, int Opts, XrdOucEnv *eP)
137{
138 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
139
140 // get mapinfo entries for file
141 std::shared_ptr<XrdOssCsiFile::puMapItem_t> pmi;
142 {
143 const std::string tpath = config_.tagParam_.makeTagFilename(path);
144 XrdOssCsiFile::mapTake(tpath, pmi);
145 }
146
147 int utret = 0;
148
149 XrdSysMutexHelper lck(pmi->mtx);
150 pmi->dpath = path;
151 if (!pmi->unlinked)
152 {
153 const int uret = successor_->Unlink(path, Opts, eP);
154 if (uret != XrdOssOK)
155 {
157 return uret;
158 }
159
160 utret = successor_->Unlink(pmi->tpath.c_str(), Opts, eP);
161 }
162
163 pmi->unlinked = true;
165
166 return (utret == -ENOENT) ? 0 : utret;
167}
168
169int XrdOssCsi::Rename(const char *oldname, const char *newname,
170 XrdOucEnv *old_env, XrdOucEnv *new_env)
171{
172 if (config_.tagParam_.isTagFile(oldname) || config_.tagParam_.isTagFile(newname)) return -ENOENT;
173
174 const std::string inew = config_.tagParam_.makeTagFilename(newname);
175 const std::string iold = config_.tagParam_.makeTagFilename(oldname);
176
177 // get mapinfo entries for both old and possibly existing newfile
178 std::shared_ptr<XrdOssCsiFile::puMapItem_t> newpmi,pmi;
179 XrdOssCsiFile::mapTake(inew, newpmi);
180 XrdOssCsiFile::mapTake(iold , pmi);
181
182 // rename to self, do nothing
183 if (newpmi == pmi)
184 {
187 return 0;
188 }
189
190 // take in consistent order
191 XrdSysMutexHelper lck(NULL), lck2(NULL);
192 // using the pointer here to get a total order, which is not
193 // guaranteed for operator<() so use std::less
194 if (std::less{}(pmi,newpmi))
195 {
196 lck.Lock(&newpmi->mtx);
197 lck2.Lock(&pmi->mtx);
198 }
199 else
200 {
201 lck2.Lock(&pmi->mtx);
202 lck.Lock(&newpmi->mtx);
203 }
204
205 if (pmi->unlinked || newpmi->unlinked)
206 {
207 // something overwrote the source or target file since we checked
208 XrdOssCsiFile::mapRelease(pmi,&lck2);
209 XrdOssCsiFile::mapRelease(newpmi,&lck);
210 return Rename(oldname, newname, old_env, new_env);
211 }
212
213 const int sret = successor_->Rename(oldname, newname, old_env, new_env);
214 if (sret<0)
215 {
216 XrdOssCsiFile::mapRelease(pmi,&lck2);
217 XrdOssCsiFile::mapRelease(newpmi,&lck);
218 return sret;
219 }
220
221 int mkdret = XrdOssOK;
222 {
223 std::string base = inew;
224 const size_t idx = base.rfind("/");
225 base = base.substr(0,idx);
226 if (!base.empty())
227 {
228 const int AMode = S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH; // 775
229 mkdret = successor_->Mkdir(base.c_str(), AMode, 1, new_env);
230 }
231 }
232
233 if (mkdret != XrdOssOK && mkdret != -EEXIST)
234 {
235 (void) successor_->Rename(newname, oldname, new_env, old_env);
236 XrdOssCsiFile::mapRelease(pmi,&lck2);
237 XrdOssCsiFile::mapRelease(newpmi,&lck);
238 return mkdret;
239 }
240
241 const int iret = successor_->Rename(iold.c_str(), inew.c_str(), old_env, new_env);
242 if (iret<0)
243 {
244 if (iret == -ENOENT)
245 {
246 // old tag did not exist, make sure there is no new tag
247 (void) successor_->Unlink(inew.c_str(), 0, new_env);
248 }
249 else
250 {
251 (void) successor_->Rename(newname, oldname, new_env, old_env);
252 XrdOssCsiFile::mapRelease(pmi,&lck2);
253 XrdOssCsiFile::mapRelease(newpmi,&lck);
254 return iret;
255 }
256 }
257
258 if (newpmi)
259 {
260 newpmi->unlinked = true;
261 }
262
263 {
265 auto mapidx_new = XrdOssCsiFile::pumap_.find(inew);
266 if (mapidx_new != XrdOssCsiFile::pumap_.end()) XrdOssCsiFile::pumap_.erase(mapidx_new);
267
268 auto mapidx = XrdOssCsiFile::pumap_.find(iold);
269 assert(mapidx != XrdOssCsiFile::pumap_.end());
270
271 XrdOssCsiFile::pumap_.erase(mapidx);
272 XrdOssCsiFile::pumap_.insert(std::make_pair(inew, pmi));
273 pmi->dpath = newname;
274 pmi->tpath = inew;
275 }
276
277 XrdOssCsiFile::mapRelease(pmi,&lck2);
278 XrdOssCsiFile::mapRelease(newpmi,&lck);
279
280 return XrdOssOK;
281}
282
283int XrdOssCsi::Truncate(const char *path, unsigned long long size, XrdOucEnv *envP)
284{
285 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
286
287 std::unique_ptr<XrdOssDF> fp(newFile("xrdt"));
288 XrdOucEnv myEnv;
289 int ret = fp->Open(path, O_RDWR, 0, envP ? *envP : myEnv);
290 if (ret != XrdOssOK)
291 {
292 return ret;
293 }
294 ret = fp->Ftruncate(size);
295 if (ret != XrdOssOK)
296 {
297 return ret;
298 }
299 long long retsz=0;
300 fp->Close(&retsz);
301 return XrdOssOK;
302}
303
304int XrdOssCsi::Reloc(const char *tident, const char *path,
305 const char *cgName, const char *anchor)
306{
307 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
308 return successor_->Reloc(tident, path, cgName, anchor);
309}
310
311int XrdOssCsi::Mkdir(const char *path, mode_t mode, int mkpath, XrdOucEnv *envP)
312{
313 if (config_.tagParam_.isTagFile(path)) return -EACCES;
314 return successor_->Mkdir(path, mode, mkpath, envP);
315}
316
317int XrdOssCsi::Create(const char *tident, const char *path, mode_t access_mode,
318 XrdOucEnv &env, int Opts)
319{
320 // tident starting with '*' is a special case to bypass OssCsi
321 if (tident && *tident == '*')
322 {
323 return successor_->Create(tident, path, access_mode, env, Opts);
324 }
325
326 if (config_.tagParam_.isTagFile(path)) return -EACCES;
327
328 // get mapinfo entries for file
329 std::shared_ptr<XrdOssCsiFile::puMapItem_t> pmi;
330 {
331 const std::string tpath = config_.tagParam_.makeTagFilename(path);
332 XrdOssCsiFile::mapTake(tpath, pmi);
333 }
334
335 XrdSysMutexHelper lck(pmi->mtx);
336 if (pmi->unlinked)
337 {
339 return Create(tident, path, access_mode, env, Opts);
340 }
341
342 const bool isTrunc = ((Opts>>8)&O_TRUNC) ? true : false;
343 const bool isExcl = ((Opts&XRDOSS_new) || ((Opts>>8)&O_EXCL)) ? true : false;
344
345 if (isTrunc && pmi->pages)
346 {
347 // truncate of already open file at open() not supported
348 XrdOssCsiFile::mapRelease(pmi, &lck);
349 return -EDEADLK;
350 }
351
352 // create file: require it not to exist (unless we're truncating) so that
353 // we can tell if we have a zero length file without stat in more cases
354
355 const int exflags = isTrunc ? 0 : ((O_EXCL<<8)|XRDOSS_new);
356
357 int ret = successor_->Create(tident, path, access_mode, env, Opts | exflags);
358 if (ret == XrdOssOK || ret == -EEXIST)
359 {
360 // success from trunc/exclusive create means the file must now be zero length
361 bool zlen = (ret == XrdOssOK) ? true : false;
362 struct stat sbuf;
363 if (!zlen && successor_->Stat(path, &sbuf, 0, &env) == XrdOssOK)
364 {
365 // had to check file size
366 if (sbuf.st_size == 0)
367 {
368 zlen = true;
369 }
370 }
371
372 // If datafile is zero length try to make empty tag file
373 if (zlen)
374 {
375 const std::string tpath = config_.tagParam_.makeTagFilename(path);
376 const int flags = O_RDWR|O_CREAT|O_TRUNC;
377 const int cropts = XRDOSS_mkpath;
378
379 std::unique_ptr<XrdOucEnv> tagEnv = tagOpenEnv(config_, env);
380
381 ret = successor_->Create(tident, tpath.c_str(), 0666, *tagEnv, (flags<<8)|cropts);
382 }
383 }
384
385 XrdOssCsiFile::mapRelease(pmi, &lck);
386
387 // may not need to return EEXIST
388 return (ret==-EEXIST && !isExcl) ? XrdOssOK : ret;
389}
390
391int XrdOssCsi::Chmod(const char *path, mode_t mode, XrdOucEnv *envP)
392{
393 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
394 return successor_->Chmod(path, mode, envP);
395}
396
397int XrdOssCsi::Remdir(const char *path, int Opts, XrdOucEnv *eP)
398{
399 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
400 const int ret = successor_->Remdir(path, Opts, eP);
401 if (ret != XrdOssOK || !config_.tagParam_.hasPrefix()) return ret;
402
403 // try to remove the corresponding directory under the tagfile directory.
404 // ignore errors
405
406 const std::string tpath = config_.tagParam_.makeBaseDirname(path);
407 (void) successor_->Remdir(tpath.c_str(), Opts, eP);
408 return XrdOssOK;
409}
410
411int XrdOssCsi::Stat(const char *path, struct stat *buff, int opts,
412 XrdOucEnv *EnvP)
413{
414 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
415 return successor_->Stat(path, buff, opts, EnvP);
416}
417
418int XrdOssCsi::StatPF(const char *path, struct stat *buff, int opts)
419{
420 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
421 if (!(opts & XrdOss::PF_dStat)) return successor_->StatPF(path, buff, opts);
422
423 buff->st_rdev = 0;
424 const int pfret = successor_->StatPF(path, buff, opts);
425 if (pfret != XrdOssOK)
426 {
427 return pfret;
428 }
429
430 std::unique_ptr<XrdOssCsiFile> fp((XrdOssCsiFile*)newFile("xrdt"));
431 XrdOucEnv myEnv;
432 const int oret = fp->Open(path, O_RDONLY, 0, myEnv);
433 if (oret != XrdOssOK)
434 {
435 return oret;
436 }
437 const int vs = fp->VerificationStatus();
438
439 long long retsz=0;
440 fp->Close(&retsz);
441
442 buff->st_rdev &= ~(XrdOss::PF_csVer | XrdOss::PF_csVun);
443 buff->st_rdev |= static_cast<dev_t>(vs);
444 return XrdOssOK;
445}
446
447int XrdOssCsi::StatXA(const char *path, char *buff, int &blen,
448 XrdOucEnv *envP)
449{
450 if (config_.tagParam_.isTagFile(path)) return -ENOENT;
451 return successor_->StatXA(path, buff, blen, envP);
452}
453
454
457 const char *config_fn,
458 const char *parms,
459 XrdOucEnv *envP)
460{
461 XrdOssCsi *myOss = new XrdOssCsi(curr_oss);
462 if (myOss->Init(Logger, config_fn, parms, envP) != XrdOssOK)
463 {
464 delete myOss;
465 return NULL;
466 }
467 return (XrdOss*)myOss;
468}
469
470std::unique_ptr<XrdOucEnv> XrdOssCsi::tagOpenEnv(const XrdOssCsiConfig &config, XrdOucEnv &env)
471{
472 // for tagfile open, start with copy of datafile environment
473 int infolen;
474 const char *info = env.Env(infolen);
475 std::unique_ptr<XrdOucEnv> newEnv(new XrdOucEnv(info, infolen, env.secEnv()));
476
477 // give space name for tag files
478 newEnv->Put("oss.cgroup", config.xrdtSpaceName().c_str());
479
480 char *tmp;
481 long long cgSize=0;
482 if ((tmp = env.Get("oss.asize")) && XrdOuca2x::a2sz(OssCsiEroute,"invalid asize",tmp,&cgSize,0))
483 {
484 cgSize=0;
485 }
486
487 if (cgSize>0)
488 {
489 char size_str[32];
490 sprintf(size_str, "%lld", 20+4*((cgSize+XrdSys::PageSize-1)/XrdSys::PageSize));
491 newEnv->Put("oss.asize", size_str);
492 }
493 else
494 {
495 newEnv->Put("oss.asize", "0");
496 }
497
498 return newEnv;
499}
#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:455
XrdVERSIONINFO(XrdOssAddStorageSystem2, XrdOssCsi) XrdSysError OssCsiEroute(0
XrdOucTrace OssCsiTrace & OssCsiEroute
Definition XrdOssCsi.cc:53
osscsi_
Definition XrdOssCsi.cc:52
#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:57
virtual int Readdir(char *buff, int blen)
Definition XrdOssCsi.cc:74
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:397
virtual int Stat(const char *path, struct stat *buff, int opts=0, XrdOucEnv *EnvP=0)
Definition XrdOssCsi.cc:411
static std::unique_ptr< XrdOucEnv > tagOpenEnv(const XrdOssCsiConfig &, XrdOucEnv &)
Definition XrdOssCsi.cc:470
virtual int Unlink(const char *path, int Opts=0, XrdOucEnv *eP=0)
Definition XrdOssCsi.cc:136
virtual int Reloc(const char *tident, const char *path, const char *cgName, const char *anchor=0)
Definition XrdOssCsi.cc:304
virtual int Init(XrdSysLogger *lp, const char *cfn)
Definition XrdOssCsi.hh:186
virtual XrdOssDF * newFile(const char *tident)
Definition XrdOssCsi.cc:105
virtual int Mkdir(const char *path, mode_t mode, int mkpath=0, XrdOucEnv *envP=0)
Definition XrdOssCsi.cc:311
virtual int Chmod(const char *path, mode_t mode, XrdOucEnv *envP=0)
Definition XrdOssCsi.cc:391
virtual int Create(const char *tident, const char *path, mode_t access_mode, XrdOucEnv &env, int Opts=0)
Definition XrdOssCsi.cc:317
virtual int Truncate(const char *path, unsigned long long size, XrdOucEnv *envP=0)
Definition XrdOssCsi.cc:283
virtual int StatXA(const char *path, char *buff, int &blen, XrdOucEnv *envP=0)
Definition XrdOssCsi.cc:447
static XrdScheduler * Sched_
Definition XrdOssCsi.hh:216
virtual int StatPF(const char *path, struct stat *buff, int opts)
Definition XrdOssCsi.cc:418
virtual int Rename(const char *oldname, const char *newname, XrdOucEnv *old_env=0, XrdOucEnv *new_env=0)
Definition XrdOssCsi.cc:169
virtual XrdOssDF * newDir(const char *tident)
Definition XrdOssCsi.cc:94
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