XRootD
XrdFrmAdminReloc.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d F r m A d m i n R e l o c . c c */
4 /* */
5 /* (c) 2008 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <cerrno>
32 #include <fcntl.h>
33 #include <cstring>
34 #include <ctime>
35 #include <cstdio>
36 #include <unistd.h>
37 #include <utime.h>
38 #include <sys/mman.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 
42 #include "XrdFrc/XrdFrcTrace.hh"
43 #include "XrdFrm/XrdFrmAdmin.hh"
44 #include "XrdFrm/XrdFrmConfig.hh"
45 #include "XrdOss/XrdOss.hh"
46 #include "XrdOss/XrdOssOpaque.hh"
47 #include "XrdOss/XrdOssPath.hh"
48 #include "XrdOss/XrdOssSpace.hh"
49 #include "XrdOuc/XrdOucEnv.hh"
51 #include "XrdOuc/XrdOucTList.hh"
52 #include "XrdSys/XrdSysPlatform.hh"
53 
54 using namespace XrdFrc;
55 using namespace XrdFrm;
56 
57 /******************************************************************************/
58 /* R e l o c */
59 /******************************************************************************/
60 
61 int XrdFrmAdmin::Reloc(char *srcLfn, char *Space)
62 {
63  static const int crOpts = (O_CREAT|O_EXCL)<<8;
64  class relocRecover
65  {public:
66  char *Lfn;
67  relocRecover() : Lfn(0) {}
68  ~relocRecover() {if (Lfn) Config.ossFS->Unlink(Lfn);}
69  } Recover;
70 
71  XrdOucTList *pP;
72  XrdOucEnv myEnv;
73  struct stat srcStat, lokStat;
74  struct utimbuf tBuff;
75  char trgLfn[1032], trgPfn[1032], trgSpace[XrdOssSpace::minSNbsz];
76  char srcLnk[1032], srcPfn[1032], srcSpace[XrdOssSpace::minSNbsz];
77  char lokPfn[1032], ASize[32], *fsTarget = 0;
78  int rc, srcLsz = 0;
79 
80 // Obtain the target space information, verify that it exists
81 //
82  if (!(pP = ParseSpace(Space, &fsTarget))) return 4;
83  strcpy(trgSpace, Space);
84  if (fsTarget) *(fsTarget-1) = ':';
85 
86 // Get the pfn for the incoming path
87 //
88  if (!Config.LocalPath(srcLfn, srcPfn, sizeof(srcPfn)-8))
89  {finalRC = 4; return 0;}
90 
91 // Make sure the source file exists and get its attributes
92 //
93  if ( lstat(srcPfn, &srcStat)) {Emsg(errno, "stat ", srcLfn); return 0;}
94  if ((srcStat.st_mode & S_IFMT) == S_IFLNK)
95  {if (stat(srcPfn, &srcStat)) {Emsg(errno, "stat ", srcLfn); return 0;}
96  if ((srcLsz = readlink(srcPfn, srcLnk, sizeof(srcLnk)-1) < 0))
97  {Emsg(errno, "read link ", srcLfn); return 0;}
98  srcLnk[srcLsz] = '\0';
99  } else *srcLnk = 0;
100  XrdOssPath::getCname(srcPfn, srcSpace);
101 
102 // Check this operation really makes sense
103 //
104  if (!strcmp(srcSpace, trgSpace)
105  || (fsTarget && !strncmp(fsTarget, srcLnk, strlen(fsTarget))))
106  {Emsg(srcLfn, " already in space ", Space); return 0;}
107 
108 // Get the current lock file time
109 //
110  strcpy(lokPfn, srcPfn); strcat(lokPfn, ".lock");
111  if (stat(lokPfn, &lokStat)) *lokPfn = '\0';
112 
113 // Generate the target lfn and pfn
114 //
115  strcpy(trgLfn, srcLfn); strcat(trgLfn, ".anew");
116  if (!Config.LocalPath(trgLfn, trgPfn, sizeof(trgPfn)))
117  {finalRC = 4; return 0;}
118 
119 // Set environmental variables
120 //
121  sprintf(ASize,"%lld", static_cast<long long>(srcStat.st_size));
122  myEnv.Put("oss.asize", ASize);
123  myEnv.Put("oss.cgroup",Space);
124 
125 // Allocate a new file in the target space
126 //
127  rc = Config.ossFS->Create("admin",trgLfn,srcStat.st_mode&S_IAMB,myEnv,crOpts);
128  if (rc) {Emsg(rc, "create placeholder for ", trgLfn); return 0;}
129 
130 // Now copy the source file to the target location. While we could possibly
131 // have done a rename, this could have potentially disrupted access to the file.
132 // Perform the reloc based on src/trg location
133 //
134  Recover.Lfn = trgPfn;
135  if (!RelocCP(srcPfn, trgPfn, srcStat.st_size)) return 0;
136 
137 // Set the time of the file to it's original value
138 //
139  tBuff.actime = srcStat.st_atime;
140  tBuff.modtime= srcStat.st_mtime;
141  if (utime(trgPfn, &tBuff)) Emsg(errno, "set mtime for ", trgPfn);
142 
143 // Set the lock file time (do not let the reloc complete unless we can)
144 //
145  if (*lokPfn)
146  {strcpy(lokPfn, trgPfn); strcat(lokPfn, ".lock");
147  tBuff.actime = lokStat.st_atime;
148  tBuff.modtime= lokStat.st_mtime;
149  if (utime(lokPfn, &tBuff)) Emsg(errno, "set mtime for ", srcLfn);
150  return 0;
151  }
152 
153 // Rename the new file to the old file
154 //
155  if ((rc = Config.ossFS->Rename(trgLfn, srcLfn)))
156  {Emsg(-rc, "rename ", trgPfn); return 0;}
157  Recover.Lfn = 0;
158 
159 // Now adjust space as needed
160 //
161  XrdOssSpace::Adjust(trgSpace, srcStat.st_size, XrdOssSpace::Pstg);
162  XrdOssSpace::Adjust(srcSpace, -srcStat.st_size, XrdOssSpace::Purg);
163 
164 // If the source was another cache file syste, we need to remove the remnants
165 //
166  if (srcLsz)
167  {if (symlink(srcLnk, trgPfn))
168  {Emsg(errno, "create symlink to ", srcLnk); return 0;}
169  if ((rc = Config.ossFS->Unlink(trgLfn)))
170  {Emsg(errno, "remove ", trgPfn); return 0;}
171  }
172 
173 // All done
174 //
175  Msg(srcLfn, " relocated from space ", srcSpace, " to ", Space);
176  return 0;
177 }
178 
179 /******************************************************************************/
180 /* R e l o c C P */
181 /******************************************************************************/
182 
183 int XrdFrmAdmin::RelocCP(const char *inFn, const char *outFn, off_t inSz)
184 {
185  static const size_t segSize = 1024*1024;
186  class ioFD
187  {public:
188  int FD;
189  ioFD() : FD(-1) {}
190  ~ioFD() {if (FD >= 0) close(FD);}
191  } In, Out;
192 
193  char *inBuff, ioBuff[segSize], *bP;
194  off_t inOff=0, Offset=0, Size=inSz, outSize=segSize, inSize=segSize;
195  size_t ioSize;
196  ssize_t rLen;
197 
198 // Open the input file
199 //
200  if ((In.FD = open(inFn, O_RDONLY)) < 0)
201  {Emsg(errno, "open ", inFn); return 1;}
202 
203 // Open the output file
204 //
205  if ((Out.FD = open(outFn, O_WRONLY)) < 0)
206  {Emsg(errno, "open ", outFn); return 1;}
207 
208 // We now copy 1MB segments using direct I/O
209 //
210  ioSize = (Size < (int)segSize ? Size : segSize);
211  while(Size)
212  {if ((inBuff = (char *)mmap(0, ioSize, PROT_READ,
213  MAP_NORESERVE|MAP_PRIVATE, In.FD, Offset)) == MAP_FAILED)
214  {Emsg(errno, "memory map ", inFn); break;}
215  if (!RelocWR(outFn, Out.FD, inBuff, ioSize, Offset)) break;
216  Size -= ioSize; Offset += ioSize;
217  if (munmap(inBuff, ioSize) < 0)
218  {Emsg(errno, "unmap memory for ", inFn); break;}
219  if (Size < (int)segSize) ioSize = Size;
220  }
221 
222 // Return if all went well, otherwise check if we can recover
223 //
224  if (!Size || Size != inSz) return Size == 0;
225  Msg("Trying traditional copy....");
226 
227 // Do a traditional copy
228 //
229  inSize = (inSz < (int)segSize ? Size : segSize);
230  while(Size)
231  {if (Size < (int)ioSize) outSize = inSize = Size;
232  bP = ioBuff;
233  while(inSize)
234  {if ((rLen = pread(In.FD, bP, inSize, inOff)) < 0)
235  {if (errno == EINTR) continue;
236  else {Emsg(errno, "read ", inFn); return 0;}
237  }
238  bP += rLen; inSize -= rLen; inOff += rLen;
239  }
240  if (!RelocWR(outFn, Out.FD, ioBuff, outSize, Offset)) return 0;
241  Size -= outSize; Offset += outSize;
242  }
243 
244 // Success
245 //
246  return 1;
247 }
248 
249 /******************************************************************************/
250 
251 int XrdFrmAdmin::RelocWR(const char *outFn,
252  int oFD, char *Buff, size_t BLen, off_t BOff)
253 {
254  ssize_t wLen;
255 
256 // Copy out a segment
257 //
258  while(BLen)
259  {if ((wLen = pwrite(oFD, Buff, BLen, BOff)) < 0)
260  {if (errno == EINTR) continue;
261  else break;
262  }
263  Buff += wLen; BLen -= wLen; BOff += wLen;
264  }
265 
266 // Check for errors
267 //
268  if (!BLen) return 1;
269  Emsg(errno, "write ", outFn);
270  return 0;
271 }
#define S_IAMB
Definition: XrdConfig.cc:159
ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset)
int stat(const char *path, struct stat *buf)
int open(const char *path, int oflag,...)
ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset)
int lstat(const char *path, struct stat *buf)
#define close(a)
Definition: XrdPosix.hh:43
XrdOss * ossFS
static int getCname(const char *path, char *Cache, char *lbuf=0, int lbsz=0)
Definition: XrdOssPath.cc:241
static const int minSNbsz
Definition: XrdOssSpace.hh:45
static void Adjust(int Gent, off_t Space, sType=Serv)
Definition: XrdOssSpace.cc:81
virtual int Create(const char *tid, const char *path, mode_t mode, XrdOucEnv &env, int opts=0)=0
virtual int Rename(const char *oPath, const char *nPath, XrdOucEnv *oEnvP=0, XrdOucEnv *nEnvP=0)=0
virtual int Unlink(const char *path, int Opts=0, XrdOucEnv *envP=0)=0
void Put(const char *varname, const char *value)
Definition: XrdOucEnv.hh:85
XrdCmsConfig Config