Bug Summary

File:tsalvaged/./../vol/vol-salvage.c
Location:line 1921, column 38
Description:Call to 'malloc' has an allocation size of 0 bytes

Annotated Source Code

1/*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10/*
11 * System: VICE-TWO
12 * Module: vol-salvage.c
13 * Institution: The Information Technology Center, Carnegie-Mellon University
14 */
15
16/* 1.2 features:
17 Correct handling of bad "." and ".." entries.
18 Message if volume has "destroyMe" flag set--but doesn't delete yet.
19 Link count bug fixed--bug was that vnodeEssence link count was unsigned
20 14 bits. Needs to be signed.
21
22 1.3 features:
23 Change to DirHandle stuff to make sure that cache entries are reused at the
24 right time (this parallels the file server change, but is not identical).
25
26 Added calls to directory salvager routines; doesn't salvage dir unless debug=1.
27
28 1.4 features:
29 Fixed bug which was causing inode link counts to go bad (thus leaking
30 disk blocks).
31Vnodes with 0 inode pointers in RW volumes are now deleted.
32 An inode with a matching inode number to the vnode is preferred to an
33 inode with a higer data version.
34 Bug is probably fixed that was causing data version to remain wrong,
35 despite assurances from the salvager to the contrary.
36
37 1.5 features:
38 Added limited salvaging: unless ForceSalvage is on, then the volume will
39 not be salvaged if the dontSalvage flag is set in the Volume Header.
40 The ForceSalvage flag is turned on if an individual volume is salvaged or
41 if the file FORCESALVAGE exists in the partition header of the file system
42 being salvaged. This isn't used for anything but could be set by vfsck.
43 A -f flag was also added to force salvage.
44
45 1.6 features:
46 It now deletes obsolete volume inodes without complaining
47
48 1.7 features:
49 Repairs rw volume headers (again).
50
51 1.8 features:
52 Correlates volume headers & inodes correctly, thus preventing occasional deletion
53 of read-only volumes...
54 No longer forces a directory salvage for volume 144 (which may be a good volume
55 at some other site!)
56 Some of the messages are cleaned up or made more explicit. One or two added.
57 Logging cleaned up.
58 A bug was fixed which forced salvage of read-only volumes without a corresponding
59 read/write volume.
60
61 1.9 features:
62 When a volume header is recreated, the new name will be "bogus.volume#"
63
64 2.0 features:
65 Directory salvaging turned on!!!
66
67 2.1 features:
68 Prints warning messages for setuid programs.
69
70 2.2 features:
71 Logs missing inode numbers.
72
73 2.3 features:
74 Increments directory version number by 200 (rather than by 1) when it is salvaged, in order to prevent problems due to the fact that a version number can be promised to a workstation before it is written to disk. If the server crashes, it may have an older version. Salvaging it could bring the version number up to the same version the workstation believed it already had a call back on.
75
76 2.4 features:
77 Locks the file /vice/vol/salvage.lock before starting. Aborts if it can't acquire the lock.
78 Time stamps on log entries.
79 Fcntl on stdout to cause all entries to be appended.
80 Problems writing to temporary files are now all detected.
81 Inode summary files are now dynamically named (so that multiple salvagers wouldn't conflict).
82 Some cleanup of error messages.
83*/
84
85
86#include <afsconfig.h>
87#include <afs/param.h>
88
89#include <afs/procmgmt.h>
90#include <roken.h>
91
92#ifdef HAVE_SYS_FILE_H1
93# include <sys/file.h>
94#endif
95
96#ifdef AFS_NT40_ENV
97#include <WINNT/afsevent.h>
98#endif
99#ifndef WCOREDUMP
100#define WCOREDUMP(x)((x) & 0200) ((x) & 0200)
101#endif
102#include <rx/xdr.h>
103#include <afs/afsint.h>
104#include <afs/afs_assert.h>
105#if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
106#if defined(AFS_VFSINCL_ENV1)
107#include <sys/vnode.h>
108#ifdef AFS_SUN5_ENV
109#include <sys/fs/ufs_inode.h>
110#else
111#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV1)
112#include <ufs/ufs/dinode.h>
113#include <ufs/ffs/fs.h>
114#else
115#include <ufs/inode.h>
116#endif
117#endif
118#else /* AFS_VFSINCL_ENV */
119#ifdef AFS_OSF_ENV
120#include <ufs/inode.h>
121#else /* AFS_OSF_ENV */
122#if !defined(AFS_LINUX20_ENV) && !defined(AFS_XBSD_ENV1) && !defined(AFS_DARWIN_ENV)
123#include <sys/inode.h>
124#endif
125#endif
126#endif /* AFS_VFSINCL_ENV */
127#endif /* AFS_SGI_ENV */
128#ifdef AFS_AIX_ENV
129#include <sys/vfs.h>
130#include <sys/lockf.h>
131#else
132#ifdef AFS_HPUX_ENV
133#include <checklist.h>
134#else
135#if defined(AFS_SGI_ENV)
136#include <mntent.h>
137#else
138#if defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
139#ifdef AFS_SUN5_ENV
140#include <sys/mnttab.h>
141#include <sys/mntent.h>
142#else
143#include <mntent.h>
144#endif
145#else
146#endif /* AFS_SGI_ENV */
147#endif /* AFS_HPUX_ENV */
148#endif
149#endif
150#ifndef AFS_NT40_ENV
151#include <afs/osi_inode.h>
152#endif
153#include <afs/cmd.h>
154#include <afs/dir.h>
155#include <afs/afsutil.h>
156#include <afs/fileutil.h>
157
158#include "nfs.h"
159#include "lwp.h"
160#include "lock.h"
161#include <afs/afssyscalls.h>
162#include "ihandle.h"
163#include "vnode.h"
164#include "volume.h"
165#include "partition.h"
166#include "daemon_com.h"
167#include "daemon_com_inline.h"
168#include "fssync.h"
169#include "volume_inline.h"
170#include "salvsync.h"
171#include "viceinode.h"
172#include "salvage.h"
173#include "volinodes.h" /* header magic number, etc. stuff */
174#include "vol-salvage.h"
175#include "common.h"
176#include "vol_internal.h"
177#include <afs/acl.h>
178#include <afs/prs_fs.h>
179
180#ifdef FSSYNC_BUILD_CLIENT1
181#include "vg_cache.h"
182#endif
183
184#ifdef AFS_NT40_ENV
185#include <pthread.h>
186#endif
187
188#ifdef AFS_OSF_ENV
189extern void *calloc();
190#endif
191static char *TimeStamp(time_t clock, int precision);
192
193
194int debug; /* -d flag */
195extern int Testing; /* -n flag */
196int ListInodeOption; /* -i flag */
197int ShowRootFiles; /* -r flag */
198int RebuildDirs; /* -sal flag */
199int Parallel = 4; /* -para X flag */
200int PartsPerDisk = 8; /* Salvage up to 8 partitions on same disk sequentially */
201int forceR = 0; /* -b flag */
202int ShowLog = 0; /* -showlog flag */
203int ShowSuid = 0; /* -showsuid flag */
204int ShowMounts = 0; /* -showmounts flag */
205int orphans = ORPH_IGNORE0; /* -orphans option */
206int Showmode = 0;
207
208
209#ifndef AFS_NT40_ENV
210int useSyslog = 0; /* -syslog flag */
211int useSyslogFacility = LOG_DAEMON(3<<3); /* -syslogfacility option */
212#endif
213
214#ifdef AFS_NT40_ENV
215int canfork = 0;
216#else
217int canfork = 1;
218#endif
219
220#define MAXPARALLEL32 32
221
222int OKToZap; /* -o flag */
223int ForceSalvage; /* If salvage should occur despite the DONT_SALVAGE flag
224 * in the volume header */
225
226FILE *logFile = 0; /* one of {/usr/afs/logs,/vice/file}/SalvageLog */
227
228#define ROOTINODE2 2 /* Root inode of a 4.2 Unix file system
229 * partition */
230/**
231 * information that is 'global' to a particular salvage job.
232 */
233struct SalvInfo {
234 Device fileSysDevice; /**< The device number of the current partition
235 * being salvaged */
236 char fileSysPath[8]; /**< The path of the mounted partition currently
237 * being salvaged, i.e. the directory containing
238 * the volume headers */
239 char *fileSysPathName; /**< NT needs this to make name pretty log. */
240 IHandle_t *VGLinkH; /**< Link handle for current volume group. */
241 int VGLinkH_cnt; /**< # of references to lnk handle. */
242 struct DiskPartition64 *fileSysPartition; /**< Partition being salvaged */
243
244#ifndef AFS_NT40_ENV
245 char *fileSysDeviceName; /**< The block device where the file system being
246 * salvaged was mounted */
247 char *filesysfulldev;
248#endif
249 int VolumeChanged; /**< Set by any routine which would change the
250 * volume in a way which would require callbacks
251 * to be broken if the volume was put back on
252 * on line by an active file server */
253
254 VolumeDiskData VolInfo; /**< A copy of the last good or salvaged volume
255 * header dealt with */
256
257 int nVolumesInInodeFile; /**< Number of read-write volumes summarized */
258 FD_t inodeFd; /**< File descriptor for inode file */
259
260 struct VolumeSummary *volumeSummaryp; /**< Holds all the volumes in a part */
261 int nVolumes; /**< Number of volumes (read-write and read-only)
262 * in volume summary */
263 struct InodeSummary *inodeSummary; /**< contains info on all the relevant
264 * inodes */
265
266 struct VnodeInfo vnodeInfo[nVNODECLASSES(((1<<1)-1)+1)]; /**< contains info on all of the
267 * vnodes in the volume that
268 * we are currently looking
269 * at */
270 int useFSYNC; /**< 0 if the fileserver is unavailable; 1 if we should try
271 * to contact the fileserver over FSYNC */
272};
273
274char *tmpdir = NULL((void *)0);
275
276
277
278/* Forward declarations */
279static int IsVnodeOrphaned(struct SalvInfo *salvinfo, VnodeId vnode);
280static int AskVolumeSummary(struct SalvInfo *salvinfo,
281 VolumeId singleVolumeNumber);
282static void MaybeAskOnline(struct SalvInfo *salvinfo, VolumeId volumeId);
283static void AskError(struct SalvInfo *salvinfo, VolumeId volumeId);
284
285#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
286static int LockVolume(struct SalvInfo *salvinfo, VolumeId volumeId);
287#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
288
289/* Uniquifier stored in the Inode */
290static Unique
291IUnique(Unique u)
292{
293#ifdef AFS_3DISPARES
294 return (u & 0x3fffff);
295#else
296#if defined(AFS_SGI_EXMAG)
297 return (u & SGI_UNIQMASK);
298#else
299 return (u);
300#endif /* AFS_SGI_EXMAG */
301#endif
302}
303
304static int
305BadError(int aerror)
306{
307 if (aerror == EPERM1 || aerror == ENXIO6 || aerror == ENOENT2)
308 return 1;
309 return 0; /* otherwise may be transient, e.g. EMFILE */
310}
311
312#define MAX_ARGS128 128
313#ifdef AFS_NT40_ENV
314char *save_args[MAX_ARGS128];
315int n_save_args = 0;
316extern pthread_t main_thread;
317childJob_t myjob = { SALVAGER_MAGIC, NOT_CHILD, "" };
318#endif
319
320/**
321 * Get the salvage lock if not already held. Hold until process exits.
322 *
323 * @param[in] locktype READ_LOCK or WRITE_LOCK
324 */
325static void
326_ObtainSalvageLock(int locktype)
327{
328 struct VLockFile salvageLock;
329 int offset = 0;
330 int nonblock = 1;
331 int code;
332
333 VLockFileInit(&salvageLock, AFSDIR_SERVER_SLVGLOCK_FILEPATHgetDirPath(AFSDIR_SERVER_SLVGLOCK_FILEPATH_ID));
334
335 code = VLockFileLock(&salvageLock, offset, locktype, nonblock);
336 if (code == EBUSY16) {
337 fprintf(stderr__stderrp,
338 "salvager: There appears to be another salvager running! "
339 "Aborted.\n");
340 Exit(1);
341 } else if (code) {
342 fprintf(stderr__stderrp,
343 "salvager: Error %d trying to acquire salvage lock! "
344 "Aborted.\n", code);
345 Exit(1);
346 }
347}
348void
349ObtainSalvageLock(void)
350{
351 _ObtainSalvageLock(WRITE_LOCK2);
352}
353void
354ObtainSharedSalvageLock(void)
355{
356 _ObtainSalvageLock(READ_LOCK1);
357}
358
359
360#ifdef AFS_SGI_XFS_IOPS_ENV
361/* Check if the given partition is mounted. For XFS, the root inode is not a
362 * constant. So we check the hard way.
363 */
364int
365IsPartitionMounted(char *part)
366{
367 FILE *mntfp;
368 struct mntent *mntent;
369
370 osi_Assert(mntfp = setmntent(MOUNTED, "r"))(void)((mntfp = setmntent(MOUNTED, "r")) || (osi_AssertFailU(
"mntfp = setmntent(MOUNTED, \"r\")", "./../vol/vol-salvage.c"
, 370), 0))
;
371 while (mntent = getmntent(mntfp)) {
372 if (!strcmp(part, mntent->mnt_dir))
373 break;
374 }
375 endmntent(mntfp);
376
377 return mntent ? 1 : 1;
378}
379#endif
380/* Check if the given inode is the root of the filesystem. */
381#ifndef AFS_SGI_XFS_IOPS_ENV
382int
383IsRootInode(struct afs_stat_ststat *status)
384{
385 /*
386 * The root inode is not a fixed value in XFS partitions. So we need to
387 * see if the partition is in the list of mounted partitions. This only
388 * affects the SalvageFileSys path, so we check there.
389 */
390 return (status->st_ino == ROOTINODE2);
391}
392#endif
393
394#ifdef AFS_AIX42_ENV
395#ifndef AFS_NAMEI_ENV1
396/* We don't want to salvage big files filesystems, since we can't put volumes on
397 * them.
398 */
399int
400CheckIfBigFilesFS(char *mountPoint, char *devName)
401{
402 struct superblock fs;
403 char name[128];
404
405 if (strncmp(devName, "/dev/", 5)) {
406 (void)sprintf(name, "/dev/%s", devName);
407 } else {
408 (void)strcpy(name, devName);
409 }
410
411 if (ReadSuper(&fs, name) < 0) {
412 Log("Unable to read superblock. Not salvaging partition %s.\n",
413 mountPoint);
414 return 1;
415 }
416 if (IsBigFilesFileSystem(&fs)) {
417 Log("Partition %s is a big files filesystem, not salvaging.\n",
418 mountPoint);
419 return 1;
420 }
421 return 0;
422}
423#endif
424#endif
425
426#ifdef AFS_NT40_ENV
427#define HDSTR "\\Device\\Harddisk"
428#define HDLEN (sizeof(HDSTR)-1) /* Length of "\Device\Harddisk" */
429int
430SameDisk(struct DiskPartition64 *p1, struct DiskPartition64 *p2)((struct DiskPartition64 *p1)->device/PartsPerDisk == (struct
DiskPartition64 *p2)->device/PartsPerDisk)
431{
432#define RES_LEN 256
433 char res1[RES_LEN];
434 char res2[RES_LEN];
435
436 static int dowarn = 1;
437
438 if (!QueryDosDevice(p1->devName, res1, RES_LEN - 1))
439 return 1;
440 if (strncmp(res1, HDSTR, HDLEN)) {
441 if (dowarn) {
442 dowarn = 0;
443 Log("WARNING: QueryDosDevice is returning %s, not %s for %s\n",
444 res1, HDSTR, p1->devName);
445 }
446 }
447 if (!QueryDosDevice(p2->devName, res2, RES_LEN - 1))
448 return 1;
449 if (strncmp(res2, HDSTR, HDLEN)) {
450 if (dowarn) {
451 dowarn = 0;
452 Log("WARNING: QueryDosDevice is returning %s, not %s for %s\n",
453 res2, HDSTR, p2->devName);
454 }
455 }
456
457 return (0 == _strnicmp(res1, res2, RES_LEN - 1));
458}
459#else
460#define SameDisk(P1, P2)((P1)->device/PartsPerDisk == (P2)->device/PartsPerDisk
)
((P1)->device/PartsPerDisk == (P2)->device/PartsPerDisk)
461#endif
462
463/* This assumes that two partitions with the same device number divided by
464 * PartsPerDisk are on the same disk.
465 */
466void
467SalvageFileSysParallel(struct DiskPartition64 *partP)
468{
469 struct job {
470 struct DiskPartition64 *partP;
471 int pid; /* Pid for this job */
472 int jobnumb; /* Log file job number */
473 struct job *nextjob; /* Next partition on disk to salvage */
474 };
475 static struct job *jobs[MAXPARALLEL32] = { 0 }; /* Need to zero this */
476 struct job *thisjob = 0;
477 static int numjobs = 0;
478 static int jobcount = 0;
479 char buf[1024];
480 int wstatus;
481 struct job *oldjob;
482 int startjob;
483 FILE *passLog;
484 char logFileName[256];
485 int i, j, pid;
486
487 if (partP) {
488 /* We have a partition to salvage. Copy it into thisjob */
489 thisjob = (struct job *)malloc(sizeof(struct job));
490 if (!thisjob) {
491 Log("Can't salvage '%s'. Not enough memory\n", partP->name);
492 return;
493 }
494 memset(thisjob, 0, sizeof(struct job));
495 thisjob->partP = partP;
496 thisjob->jobnumb = jobcount;
497 jobcount++;
498 } else if (jobcount == 0) {
499 /* We are asking to wait for all jobs (partp == 0), yet we never
500 * started any.
501 */
502 Log("No file system partitions named %s* found; not salvaged\n",
503 VICE_PARTITION_PREFIX"/vicep");
504 return;
505 }
506
507 if (debug || Parallel == 1) {
508 if (thisjob) {
509 SalvageFileSys(thisjob->partP, 0);
510 free(thisjob);
511 }
512 return;
513 }
514
515 if (thisjob) {
516 /* Check to see if thisjob is for a disk that we are already
517 * salvaging. If it is, link it in as the next job to do. The
518 * jobs array has 1 entry per disk being salvages. numjobs is
519 * the total number of disks currently being salvaged. In
520 * order to keep thejobs array compact, when a disk is
521 * completed, the hightest element in the jobs array is moved
522 * down to now open slot.
523 */
524 for (j = 0; j < numjobs; j++) {
525 if (SameDisk(jobs[j]->partP, thisjob->partP)((jobs[j]->partP)->device/PartsPerDisk == (thisjob->
partP)->device/PartsPerDisk)
) {
526 /* On same disk, add it to this list and return */
527 thisjob->nextjob = jobs[j]->nextjob;
528 jobs[j]->nextjob = thisjob;
529 thisjob = 0;
530 break;
531 }
532 }
533 }
534
535 /* Loop until we start thisjob or until all existing jobs are finished */
536 while (thisjob || (!partP && (numjobs > 0))) {
537 startjob = -1; /* No new job to start */
538
539 if ((numjobs >= Parallel) || (!partP && (numjobs > 0))) {
540 /* Either the max jobs are running or we have to wait for all
541 * the jobs to finish. In either case, we wait for at least one
542 * job to finish. When it's done, clean up after it.
543 */
544 pid = wait(&wstatus);
545 osi_Assert(pid != -1)(void)((pid != -1) || (osi_AssertFailU("pid != -1", "./../vol/vol-salvage.c"
, 545), 0))
;
546 for (j = 0; j < numjobs; j++) { /* Find which job it is */
547 if (pid == jobs[j]->pid)
548 break;
549 }
550 osi_Assert(j < numjobs)(void)((j < numjobs) || (osi_AssertFailU("j < numjobs",
"./../vol/vol-salvage.c", 550), 0))
;
551 if (WCOREDUMP(wstatus)((wstatus) & 0200)) { /* Say if the job core dumped */
552 Log("Salvage of %s core dumped!\n", jobs[j]->partP->name);
553 }
554
555 numjobs--; /* job no longer running */
556 oldjob = jobs[j]; /* remember */
557 jobs[j] = jobs[j]->nextjob; /* Step to next part on same disk */
558 free(oldjob); /* free the old job */
559
560 /* If there is another partition on the disk to salvage, then
561 * say we will start it (startjob). If not, then put thisjob there
562 * and say we will start it.
563 */
564 if (jobs[j]) { /* Another partitions to salvage */
565 startjob = j; /* Will start it */
566 } else { /* There is not another partition to salvage */
567 if (thisjob) {
568 jobs[j] = thisjob; /* Add thisjob */
569 thisjob = 0;
570 startjob = j; /* Will start it */
571 } else {
572 jobs[j] = jobs[numjobs]; /* Move last job up to this slot */
573 startjob = -1; /* Don't start it - already running */
574 }
575 }
576 } else {
577 /* We don't have to wait for a job to complete */
578 if (thisjob) {
579 jobs[numjobs] = thisjob; /* Add this job */
580 thisjob = 0;
581 startjob = numjobs; /* Will start it */
582 }
583 }
584
585 /* Start up a new salvage job on a partition in job slot "startjob" */
586 if (startjob != -1) {
587 if (!Showmode)
588 Log("Starting salvage of file system partition %s\n",
589 jobs[startjob]->partP->name);
590#ifdef AFS_NT40_ENV
591 /* For NT, we not only fork, but re-exec the salvager. Pass in the
592 * commands and pass the child job number via the data path.
593 */
594 pid =
595 nt_SalvagePartition(jobs[startjob]->partP->name,
596 jobs[startjob]->jobnumb);
597 jobs[startjob]->pid = pid;
598 numjobs++;
599#else
600 pid = Fork();
601 if (pid) {
602 jobs[startjob]->pid = pid;
603 numjobs++;
604 } else {
605 int fd;
606
607 ShowLog = 0;
608 for (fd = 0; fd < 16; fd++)
609 close(fd);
610 open(OS_DIRSEP"/", 0);
611 dup2(0, 1);
612 dup2(0, 2);
613#ifndef AFS_NT40_ENV
614 if (useSyslog) {
615 openlog("salvager", LOG_PID0x01, useSyslogFacility);
616 } else
617#endif
618 {
619 snprintf(logFileName, sizeof logFileName, "%s.%d",
620 AFSDIR_SERVER_SLVGLOG_FILEPATHgetDirPath(AFSDIR_SERVER_SLVGLOG_FILEPATH_ID),
621 jobs[startjob]->jobnumb);
622 logFile = afs_fopenfopen(logFileName, "w");
623 }
624 if (!logFile)
625 logFile = stdout__stdoutp;
626
627 SalvageFileSys1(jobs[startjob]->partP, 0);
628 Exit(0);
629 }
630#endif
631 }
632 } /* while ( thisjob || (!partP && numjobs > 0) ) */
633
634 /* If waited for all jobs to complete, now collect log files and return */
635#ifndef AFS_NT40_ENV
636 if (!useSyslog) /* if syslogging - no need to collect */
637#endif
638 if (!partP) {
639 for (i = 0; i < jobcount; i++) {
640 snprintf(logFileName, sizeof logFileName, "%s.%d",
641 AFSDIR_SERVER_SLVGLOG_FILEPATHgetDirPath(AFSDIR_SERVER_SLVGLOG_FILEPATH_ID), i);
642 if ((passLog = afs_fopenfopen(logFileName, "r"))) {
643 while (fgets(buf, sizeof(buf), passLog)) {
644 fputs(buf, logFile);
645 }
646 fclose(passLog);
647 }
648 (void)unlink(logFileName);
649 }
650 fflush(logFile);
651 }
652 return;
653}
654
655
656void
657SalvageFileSys(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
658{
659 if (!canfork || debug || Fork() == 0) {
660 SalvageFileSys1(partP, singleVolumeNumber);
661 if (canfork && !debug) {
662 ShowLog = 0;
663 Exit(0);
664 }
665 } else
666 Wait("SalvageFileSys");
667}
668
669char *
670get_DevName(char *pbuffer, char *wpath)
671{
672 char pbuf[128], *ptr;
673 strcpy(pbuf, pbuffer);
674 ptr = (char *)strrchr(pbuf, OS_DIRSEPC'/');
675 if (ptr) {
676 *ptr = '\0';
677 strcpy(wpath, pbuf);
678 } else
679 return NULL((void *)0);
680 ptr = (char *)strrchr(pbuffer, OS_DIRSEPC'/');
681 if (ptr) {
682 strcpy(pbuffer, ptr + 1);
683 return pbuffer;
684 } else
685 return NULL((void *)0);
686}
687
688void
689SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
690{
691 char *name, *tdir;
692 char inodeListPath[256];
693 FD_t inodeFile = INVALID_FD((FD_t)-1);
694 static char tmpDevName[100];
695 static char wpath[100];
696 struct VolumeSummary *vsp, *esp;
697 int i, j;
698 int code;
699 int tries = 0;
700 struct SalvInfo l_salvinfo;
701 struct SalvInfo *salvinfo = &l_salvinfo;
702
703 retry:
704 memset(salvinfo, 0, sizeof(*salvinfo));
705
706 tries++;
707 if (inodeFile != INVALID_FD((FD_t)-1)) {
708 OS_CLOSE(inodeFile)close(inodeFile);
709 inodeFile = INVALID_FD((FD_t)-1);
710 }
711 if (tries > VOL_MAX_CHECKOUT_RETRIES10) {
712 Abort("Raced too many times with fileserver restarts while trying to "
713 "checkout/lock volumes; Aborted\n");
714 }
715#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
716 if (tries > 1) {
717 /* unlock all previous volume locks, since we're about to lock them
718 * again */
719 VLockFileReinit(&partP->volLockFile);
720 }
721#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
722
723 salvinfo->fileSysPartition = partP;
724 salvinfo->fileSysDevice = salvinfo->fileSysPartition->device;
725 salvinfo->fileSysPathName = VPartitionPath(salvinfo->fileSysPartition);
726
727#ifdef AFS_NT40_ENV
728 /* Opendir can fail on "C:" but not on "C:\" if C is empty! */
729 (void)sprintf(salvinfo->fileSysPath, "%s" OS_DIRSEP"/", salvinfo->fileSysPathName);
730 name = partP->devName;
731#else
732 strlcpy(salvinfo->fileSysPath, salvinfo->fileSysPathName, sizeof(salvinfo->fileSysPath));
733 strcpy(tmpDevName, partP->devName);
734 name = get_DevName(tmpDevName, wpath);
735 salvinfo->fileSysDeviceName = name;
736 salvinfo->filesysfulldev = wpath;
737#endif
738
739 if (singleVolumeNumber) {
740#if !(defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL))
741 /* only non-DAFS locks the partition when salvaging a single volume;
742 * DAFS will lock the individual volumes in the VG */
743 VLockPartition(partP->name);
744#endif /* !(AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL) */
745
746 ForceSalvage = 1;
747
748 /* salvageserver already setup fssync conn for us */
749 if ((programType != salvageServer) && !VConnectFS()) {
750 Abort("Couldn't connect to file server\n");
751 }
752
753 salvinfo->useFSYNC = 1;
754 AskOffline(salvinfo, singleVolumeNumber);
755#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
756 if (LockVolume(salvinfo, singleVolumeNumber)) {
757 goto retry;
758 }
759#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
760
761 } else {
762 salvinfo->useFSYNC = 0;
763 VLockPartition(partP->name);
764 if (ForceSalvage) {
765 ForceSalvage = 1;
766 } else {
767 ForceSalvage = UseTheForceLuke(salvinfo->fileSysPath);
768 }
769 if (!Showmode)
770 Log("SALVAGING FILE SYSTEM PARTITION %s (device=%s%s)\n",
771 partP->name, name, (Testing ? "(READONLY mode)" : ""));
772 if (ForceSalvage)
773 Log("***Forced salvage of all volumes on this partition***\n");
774 }
775
776
777 /*
778 * Remove any leftover /vicepa/salvage.inodes.* or /vicepa/salvage.temp.*
779 * files
780 */
781 {
782 DIR *dirp;
783 struct dirent *dp;
784
785 osi_Assert((dirp = opendir(salvinfo->fileSysPath)) != NULL)(void)(((dirp = opendir(salvinfo->fileSysPath)) != ((void *
)0)) || (osi_AssertFailU("(dirp = opendir(salvinfo->fileSysPath)) != NULL"
, "./../vol/vol-salvage.c", 785), 0))
;
786 while ((dp = readdir(dirp))) {
787 if (!strncmp(dp->d_name, "salvage.inodes.", 15)
788 || !strncmp(dp->d_name, "salvage.temp.", 13)) {
789 char npath[1024];
790 Log("Removing old salvager temp files %s\n", dp->d_name);
791 strcpy(npath, salvinfo->fileSysPath);
792 strcat(npath, OS_DIRSEP"/");
793 strcat(npath, dp->d_name);
794 OS_UNLINK(npath)unlink(npath);
795 }
796 }
797 closedir(dirp);
798 }
799 tdir = (tmpdir ? tmpdir : salvinfo->fileSysPath);
800#ifdef AFS_NT40_ENV
801 (void)_putenv("TMP="); /* If "TMP" is set, then that overrides tdir. */
802 (void)strncpy(inodeListPath, _tempnam(tdir, "salvage.inodes."), 255);
803#else
804 snprintf(inodeListPath, 255, "%s" OS_DIRSEP"/" "salvage.inodes.%s.%d", tdir, name,
805 getpid());
806#endif
807
808 inodeFile = OS_OPEN(inodeListPath, O_RDWR|O_TRUNC|O_CREAT, 0666)open(inodeListPath, 0x0002|0x0400|0x0200, 0666);
809 if (inodeFile == INVALID_FD((FD_t)-1)) {
810 Abort("Error %d when creating inode description file %s; not salvaged\n", errno(* __error()), inodeListPath);
811 }
812#ifdef AFS_NT40_ENV
813 /* Using nt_unlink here since we're really using the delete on close
814 * semantics of unlink. In most places in the salvager, we really do
815 * mean to unlink the file at that point. Those places have been
816 * modified to actually do that so that the NT crt can be used there.
817 *
818 * jaltman - On NT delete on close cannot be applied to a file while the
819 * process has an open file handle that does not have DELETE file
820 * access and FILE_SHARE_DELETE. fopen() calls CreateFile() without
821 * delete privileges. As a result the nt_unlink() call will always
822 * fail.
823 */
824 code = nt_unlink(inodeListPath);
825#else
826 code = unlink(inodeListPath);
827#endif
828 if (code < 0) {
829 Log("Error %d when trying to unlink %s\n", errno(* __error()), inodeListPath);
830 }
831
832 if (GetInodeSummary(salvinfo, inodeFile, singleVolumeNumber) < 0) {
833 OS_CLOSE(inodeFile)close(inodeFile);
834 return;
835 }
836 salvinfo->inodeFd = inodeFile;
837 if (salvinfo->inodeFd == INVALID_FD((FD_t)-1))
838 Abort("Temporary file %s is missing...\n", inodeListPath);
839 OS_SEEK(salvinfo->inodeFd, 0L, SEEK_SET)lseek(salvinfo->inodeFd, (off_t) (0L), 0);
840 if (ListInodeOption) {
841 PrintInodeList(salvinfo);
842 if (singleVolumeNumber) {
843 /* We've checked out the volume from the fileserver, and we need
844 * to give it back. We don't know if the volume exists or not,
845 * so we don't know whether to AskOnline or not. Try to determine
846 * if the volume exists by trying to read the volume header, and
847 * AskOnline if it is readable. */
848 MaybeAskOnline(salvinfo, singleVolumeNumber);
849 }
850 return;
851 }
852 /* enumerate volumes in the partition.
853 * figure out sets of read-only + rw volumes.
854 * salvage each set, read-only volumes first, then read-write.
855 * Fix up inodes on last volume in set (whether it is read-write
856 * or read-only).
857 */
858 if (GetVolumeSummary(salvinfo, singleVolumeNumber)) {
859 goto retry;
860 }
861
862 for (i = j = 0, vsp = salvinfo->volumeSummaryp, esp = vsp + salvinfo->nVolumes;
863 i < salvinfo->nVolumesInInodeFile; i = j) {
864 VolumeId rwvid = salvinfo->inodeSummary[i].RWvolumeId;
865 for (j = i;
866 j < salvinfo->nVolumesInInodeFile && salvinfo->inodeSummary[j].RWvolumeId == rwvid;
867 j++) {
868 VolumeId vid = salvinfo->inodeSummary[j].volumeId;
869 struct VolumeSummary *tsp;
870 /* Scan volume list (from partition root directory) looking for the
871 * current rw volume number in the volume list from the inode scan.
872 * If there is one here that is not in the inode volume list,
873 * delete it now. */
874 for (; vsp < esp && (vsp->header.parent < rwvid); vsp++) {
875 if (vsp->fileName)
876 DeleteExtraVolumeHeaderFile(salvinfo, vsp);
877 }
878 /* Now match up the volume summary info from the root directory with the
879 * entry in the volume list obtained from scanning inodes */
880 salvinfo->inodeSummary[j].volSummary = NULL((void *)0);
881 for (tsp = vsp; tsp < esp && (tsp->header.parent == rwvid); tsp++) {
882 if (tsp->header.id == vid) {
883 salvinfo->inodeSummary[j].volSummary = tsp;
884 tsp->fileName = 0;
885 break;
886 }
887 }
888 }
889 /* Salvage the group of volumes (several read-only + 1 read/write)
890 * starting with the current read-only volume we're looking at.
891 */
892#ifdef AFS_NT40_ENV
893 nt_SalvageVolumeGroup(salvinfo, &salvinfo->inodeSummary[i], j - i);
894#else
895 DoSalvageVolumeGroup(salvinfo, &salvinfo->inodeSummary[i], j - i);
896#endif /* AFS_NT40_ENV */
897
898 }
899
900 /* Delete any additional volumes that were listed in the partition but which didn't have any corresponding inodes */
901 for (; vsp < esp; vsp++) {
902 if (vsp->fileName)
903 DeleteExtraVolumeHeaderFile(salvinfo, vsp);
904 }
905
906 if (!singleVolumeNumber) /* Remove the FORCESALVAGE file */
907 RemoveTheForce(salvinfo->fileSysPath);
908
909 if (!Testing && singleVolumeNumber) {
910 int foundSVN = 0;
911#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
912 /* unlock vol headers so the fs can attach them when we AskOnline */
913 VLockFileReinit(&salvinfo->fileSysPartition->volLockFile);
914#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
915
916 /* Step through the volumeSummary list and set all volumes on-line.
917 * Most volumes were taken off-line in GetVolumeSummary.
918 * If a volume was deleted, don't tell the fileserver anything, since
919 * we already told the fileserver the volume was deleted back when we
920 * we destroyed the volume header.
921 * Also, make sure we bring the singleVolumeNumber back online first.
922 */
923
924 for (j = 0; j < salvinfo->nVolumes; j++) {
925 if (salvinfo->volumeSummaryp[j].header.id == singleVolumeNumber) {
926 foundSVN = 1;
927 if (!salvinfo->volumeSummaryp[j].deleted) {
928 AskOnline(salvinfo, singleVolumeNumber);
929 }
930 }
931 }
932
933 if (!foundSVN) {
934 /* If singleVolumeNumber is not in our volumeSummary, it means that
935 * at least one other volume in the VG is on the partition, but the
936 * RW volume is not. We've already AskOffline'd it by now, though,
937 * so make sure we don't still have the volume checked out. */
938 AskDelete(salvinfo, singleVolumeNumber);
939 }
940
941 for (j = 0; j < salvinfo->nVolumes; j++) {
942 if (salvinfo->volumeSummaryp[j].header.id != singleVolumeNumber) {
943 if (!salvinfo->volumeSummaryp[j].deleted) {
944 AskOnline(salvinfo, salvinfo->volumeSummaryp[j].header.id);
945 }
946 }
947 }
948 } else {
949 if (!Showmode)
950 Log("SALVAGING OF PARTITION %s%s COMPLETED\n",
951 salvinfo->fileSysPartition->name, (Testing ? " (READONLY mode)" : ""));
952 }
953
954 OS_CLOSE(inodeFile)close(inodeFile); /* SalvageVolumeGroup was the last which needed it. */
955}
956
957void
958DeleteExtraVolumeHeaderFile(struct SalvInfo *salvinfo, struct VolumeSummary *vsp)
959{
960 char path[64];
961 sprintf(path, "%s" OS_DIRSEP"/" "%s", salvinfo->fileSysPath, vsp->fileName);
962
963 if (!Showmode)
964 Log("The volume header file %s is not associated with any actual data (%sdeleted)\n", path, (Testing ? "would have been " : ""));
965 if (!Testing) {
966 afs_int32 code;
967 code = VDestroyVolumeDiskHeader(salvinfo->fileSysPartition, vsp->header.id, vsp->header.parent);
968 if (code) {
969 Log("Error %ld destroying volume disk header for volume %lu\n",
970 afs_printable_int32_ld(code),
971 afs_printable_uint32_lu(vsp->header.id));
972 }
973
974 /* make sure we actually delete the fileName file; ENOENT
975 * is fine, since VDestroyVolumeDiskHeader probably already
976 * unlinked it */
977 if (unlink(path) && errno(* __error()) != ENOENT2) {
978 Log("Unable to unlink %s (errno = %d)\n", path, errno(* __error()));
979 }
980 if (salvinfo->useFSYNC) {
981 AskDelete(salvinfo, vsp->header.id);
982 }
983 vsp->deleted = 1;
984 }
985 vsp->fileName = 0;
986}
987
988int
989CompareInodes(const void *_p1, const void *_p2)
990{
991 const struct ViceInodeInfo *p1 = _p1;
992 const struct ViceInodeInfo *p2 = _p2;
993 if (p1->u.vnode.vnodeNumber == INODESPECIAL0xffffffff
994 || p2->u.vnode.vnodeNumber == INODESPECIAL0xffffffff) {
995 VolumeId p1rwid, p2rwid;
996 p1rwid =
997 (p1->u.vnode.vnodeNumber ==
998 INODESPECIAL0xffffffff ? p1->u.special.parentId : p1->u.vnode.volumeId);
999 p2rwid =
1000 (p2->u.vnode.vnodeNumber ==
1001 INODESPECIAL0xffffffff ? p2->u.special.parentId : p2->u.vnode.volumeId);
1002 if (p1rwid < p2rwid)
1003 return -1;
1004 if (p1rwid > p2rwid)
1005 return 1;
1006 if (p1->u.vnode.vnodeNumber == INODESPECIAL0xffffffff
1007 && p2->u.vnode.vnodeNumber == INODESPECIAL0xffffffff) {
1008 if (p1->u.vnode.volumeId == p2->u.vnode.volumeId)
1009 return (p1->u.special.type < p2->u.special.type ? -1 : 1);
1010 if (p1->u.vnode.volumeId == p1rwid)
1011 return -1;
1012 if (p2->u.vnode.volumeId == p2rwid)
1013 return 1;
1014 return (p1->u.vnode.volumeId < p2->u.vnode.volumeId ? -1 : 1);
1015 }
1016 if (p1->u.vnode.vnodeNumber != INODESPECIAL0xffffffff)
1017 return (p2->u.vnode.volumeId == p2rwid ? 1 : -1);
1018 return (p1->u.vnode.volumeId == p1rwid ? -1 : 1);
1019 }
1020 if (p1->u.vnode.volumeId < p2->u.vnode.volumeId)
1021 return -1;
1022 if (p1->u.vnode.volumeId > p2->u.vnode.volumeId)
1023 return 1;
1024 if (p1->u.vnode.vnodeNumber < p2->u.vnode.vnodeNumber)
1025 return -1;
1026 if (p1->u.vnode.vnodeNumber > p2->u.vnode.vnodeNumber)
1027 return 1;
1028 /* The following tests are reversed, so that the most desirable
1029 * of several similar inodes comes first */
1030 if (p1->u.vnode.vnodeUniquifier > p2->u.vnode.vnodeUniquifier) {
1031#ifdef AFS_3DISPARES
1032 if (p1->u.vnode.vnodeUniquifier > 3775414 /* 90% of 4.2M */ &&
1033 p2->u.vnode.vnodeUniquifier < 419490 /* 10% of 4.2M */ )
1034 return 1;
1035#endif
1036#ifdef AFS_SGI_EXMAG
1037 if (p1->u.vnode.vnodeUniquifier > 15099494 /* 90% of 16M */ &&
1038 p2->u.vnode.vnodeUniquifier < 1677721 /* 10% of 16M */ )
1039 return 1;
1040#endif
1041 return -1;
1042 }
1043 if (p1->u.vnode.vnodeUniquifier < p2->u.vnode.vnodeUniquifier) {
1044#ifdef AFS_3DISPARES
1045 if (p2->u.vnode.vnodeUniquifier > 3775414 /* 90% of 4.2M */ &&
1046 p1->u.vnode.vnodeUniquifier < 419490 /* 10% of 4.2M */ )
1047 return -1;
1048#endif
1049#ifdef AFS_SGI_EXMAG
1050 if (p2->u.vnode.vnodeUniquifier > 15099494 /* 90% of 16M */ &&
1051 p1->u.vnode.vnodeUniquifier < 1677721 /* 10% of 16M */ )
1052 return 1;
1053#endif
1054 return 1;
1055 }
1056 if (p1->u.vnode.inodeDataVersion > p2->u.vnode.inodeDataVersion) {
1057#ifdef AFS_3DISPARES
1058 if (p1->u.vnode.inodeDataVersion > 1887437 /* 90% of 2.1M */ &&
1059 p2->u.vnode.inodeDataVersion < 209716 /* 10% of 2.1M */ )
1060 return 1;
1061#endif
1062#ifdef AFS_SGI_EXMAG
1063 if (p1->u.vnode.inodeDataVersion > 15099494 /* 90% of 16M */ &&
1064 p2->u.vnode.inodeDataVersion < 1677721 /* 10% of 16M */ )
1065 return 1;
1066#endif
1067 return -1;
1068 }
1069 if (p1->u.vnode.inodeDataVersion < p2->u.vnode.inodeDataVersion) {
1070#ifdef AFS_3DISPARES
1071 if (p2->u.vnode.inodeDataVersion > 1887437 /* 90% of 2.1M */ &&
1072 p1->u.vnode.inodeDataVersion < 209716 /* 10% of 2.1M */ )
1073 return -1;
1074#endif
1075#ifdef AFS_SGI_EXMAG
1076 if (p2->u.vnode.inodeDataVersion > 15099494 /* 90% of 16M */ &&
1077 p1->u.vnode.inodeDataVersion < 1677721 /* 10% of 16M */ )
1078 return 1;
1079#endif
1080 return 1;
1081 }
1082 return 0;
1083}
1084
1085void
1086CountVolumeInodes(struct ViceInodeInfo *ip, int maxInodes,
1087 struct InodeSummary *summary)
1088{
1089 VolumeId volume = ip->u.vnode.volumeId;
1090 VolumeId rwvolume = volume;
1091 int n, nSpecial;
1092 Unique maxunique;
1093 n = nSpecial = 0;
1094 maxunique = 0;
1095 while (maxInodes-- && volume == ip->u.vnode.volumeId) {
1096 n++;
1097 if (ip->u.vnode.vnodeNumber == INODESPECIAL0xffffffff) {
1098 nSpecial++;
1099 rwvolume = ip->u.special.parentId;
1100 /* This isn't quite right, as there could (in error) be different
1101 * parent inodes in different special vnodes */
1102 } else {
1103 if (maxunique < ip->u.vnode.vnodeUniquifier)
1104 maxunique = ip->u.vnode.vnodeUniquifier;
1105 }
1106 ip++;
1107 }
1108 summary->volumeId = volume;
1109 summary->RWvolumeId = rwvolume;
1110 summary->nInodes = n;
1111 summary->nSpecialInodes = nSpecial;
1112 summary->maxUniquifier = maxunique;
1113}
1114
1115int
1116OnlyOneVolume(struct ViceInodeInfo *inodeinfo, afs_uint32 singleVolumeNumber, void *rock)
1117{
1118 if (inodeinfo->u.vnode.vnodeNumber == INODESPECIAL0xffffffff)
1119 return (inodeinfo->u.special.parentId == singleVolumeNumber);
1120 return (inodeinfo->u.vnode.volumeId == singleVolumeNumber);
1121}
1122
1123/* GetInodeSummary
1124 *
1125 * Collect list of inodes in file named by path. If a truly fatal error,
1126 * unlink the file and abort. For lessor errors, return -1. The file will
1127 * be unlinked by the caller.
1128 */
1129int
1130GetInodeSummary(struct SalvInfo *salvinfo, FD_t inodeFile, VolumeId singleVolumeNumber)
1131{
1132 int forceSal, err;
1133 int code;
1134 struct ViceInodeInfo *ip, *ip_save;
1135 struct InodeSummary summary;
1136 char summaryFileName[50];
1137 FD_t summaryFile = INVALID_FD((FD_t)-1);
1138#ifdef AFS_NT40_ENV
1139 char *dev = salvinfo->fileSysPath;
1140 char *wpath = salvinfo->fileSysPath;
1141#else
1142 char *dev = salvinfo->fileSysDeviceName;
1143 char *wpath = salvinfo->filesysfulldev;
1144#endif
1145 char *part = salvinfo->fileSysPath;
1146 char *tdir;
1147 int i;
1148 int retcode = 0;
1149 int deleted = 0;
1150 afs_sfsize_t st_size;
1151
1152 /* This file used to come from vfsck; cobble it up ourselves now... */
1153 if ((err =
1154 ListViceInodes(dev, salvinfo->fileSysPath, inodeFile,
1155 singleVolumeNumber ? OnlyOneVolume : 0,
1156 singleVolumeNumber, &forceSal, forceR, wpath, NULL((void *)0))) < 0) {
1157 if (err == -2) {
1158 Log("*** I/O error %d when writing a tmp inode file; Not salvaged %s ***\nIncrease space on partition or use '-tmpdir'\n", errno(* __error()), dev);
1159 retcode = -1;
1160 goto error;
1161 }
1162 Abort("Unable to get inodes for \"%s\"; not salvaged\n", dev);
1163 }
1164 if (forceSal && !ForceSalvage) {
1165 Log("***Forced salvage of all volumes on this partition***\n");
1166 ForceSalvage = 1;
1167 }
1168 OS_SEEK(inodeFile, 0L, SEEK_SET)lseek(inodeFile, (off_t) (0L), 0);
1169 salvinfo->inodeFd = inodeFile;
1170 if (salvinfo->inodeFd == INVALID_FD((FD_t)-1) ||
1171 (st_size = OS_SIZE(salvinfo->inodeFd)ih_size(salvinfo->inodeFd)) == -1) {
1172 Abort("No inode description file for \"%s\"; not salvaged\n", dev);
1173 }
1174 tdir = (tmpdir ? tmpdir : part);
1175#ifdef AFS_NT40_ENV
1176 (void)_putenv("TMP="); /* If "TMP" is set, then that overrides tdir. */
1177 (void)strcpy(summaryFileName, _tempnam(tdir, "salvage.temp."));
1178#else
1179 snprintf(summaryFileName, sizeof summaryFileName,
1180 "%s" OS_DIRSEP"/" "salvage.temp.%d", tdir, getpid());
1181#endif
1182 summaryFile = OS_OPEN(summaryFileName, O_RDWR|O_APPEND|O_CREAT, 0666)open(summaryFileName, 0x0002|0x0008|0x0200, 0666);
1183 if (summaryFile == INVALID_FD((FD_t)-1)) {
1184 Abort("Unable to create inode summary file\n");
1185 }
1186
1187#ifdef AFS_NT40_ENV
1188 /* Using nt_unlink here since we're really using the delete on close
1189 * semantics of unlink. In most places in the salvager, we really do
1190 * mean to unlink the file at that point. Those places have been
1191 * modified to actually do that so that the NT crt can be used there.
1192 *
1193 * jaltman - As commented elsewhere, this cannot work because fopen()
1194 * does not open files with DELETE and FILE_SHARE_DELETE.
1195 */
1196 code = nt_unlink(summaryFileName);
1197#else
1198 code = unlink(summaryFileName);
1199#endif
1200 if (code < 0) {
1201 Log("Error %d when trying to unlink %s\n", errno(* __error()), summaryFileName);
1202 }
1203
1204 if (!canfork || debug || Fork() == 0) {
1205 int nInodes = st_size / sizeof(struct ViceInodeInfo);
1206 if (nInodes == 0) {
1207 OS_CLOSE(summaryFile)close(summaryFile);
1208 if (!singleVolumeNumber) /* Remove the FORCESALVAGE file */
1209 RemoveTheForce(salvinfo->fileSysPath);
1210 else {
1211 struct VolumeSummary *vsp;
1212 int i;
1213 int foundSVN = 0;
1214
1215 GetVolumeSummary(salvinfo, singleVolumeNumber);
1216
1217 for (i = 0, vsp = salvinfo->volumeSummaryp; i < salvinfo->nVolumes; i++) {
1218 if (vsp->fileName) {
1219 if (vsp->header.id == singleVolumeNumber) {
1220 foundSVN = 1;
1221 }
1222 DeleteExtraVolumeHeaderFile(salvinfo, vsp);
1223 }
1224 }
1225
1226 if (!foundSVN) {
1227 if (Testing) {
1228 MaybeAskOnline(salvinfo, singleVolumeNumber);
1229 } else {
1230 /* make sure we get rid of stray .vol headers, even if
1231 * they're not in our volume summary (might happen if
1232 * e.g. something else created them and they're not in the
1233 * fileserver VGC) */
1234 VDestroyVolumeDiskHeader(salvinfo->fileSysPartition,
1235 singleVolumeNumber, 0 /*parent*/);
1236 AskDelete(salvinfo, singleVolumeNumber);
1237 }
1238 }
1239 }
1240 Log("%s vice inodes on %s; not salvaged\n",
1241 singleVolumeNumber ? "No applicable" : "No", dev);
1242 retcode = -1;
1243 deleted = 1;
1244 goto error;
1245 }
1246 ip = (struct ViceInodeInfo *)malloc(nInodes*sizeof(struct ViceInodeInfo));
1247 if (ip == NULL((void *)0)) {
1248 OS_CLOSE(summaryFile)close(summaryFile);
1249 Abort
1250 ("Unable to allocate enough space to read inode table; %s not salvaged\n",
1251 dev);
1252 }
1253 if (OS_READ(salvinfo->inodeFd, ip, st_size)read(salvinfo->inodeFd, ip, st_size) != st_size) {
1254 OS_CLOSE(summaryFile)close(summaryFile);
1255 Abort("Unable to read inode table; %s not salvaged\n", dev);
1256 }
1257 qsort(ip, nInodes, sizeof(struct ViceInodeInfo), CompareInodes);
1258 if (OS_SEEK(salvinfo->inodeFd, 0, SEEK_SET)lseek(salvinfo->inodeFd, (off_t) (0), 0) == -1
1259 || OS_WRITE(salvinfo->inodeFd, ip, st_size)write(salvinfo->inodeFd, ip, st_size) != st_size) {
1260 OS_CLOSE(summaryFile)close(summaryFile);
1261 Abort("Unable to rewrite inode table; %s not salvaged\n", dev);
1262 }
1263 summary.index = 0;
1264 ip_save = ip;
1265 while (nInodes) {
1266 CountVolumeInodes(ip, nInodes, &summary);
1267 if (OS_WRITE(summaryFile, &summary, sizeof(summary))write(summaryFile, &summary, sizeof(summary)) != sizeof(summary)) {
1268 Log("Difficulty writing summary file (errno = %d); %s not salvaged\n", errno(* __error()), dev);
1269 OS_CLOSE(summaryFile)close(summaryFile);
1270 retcode = -1;
1271 goto error;
1272 }
1273 summary.index += (summary.nInodes);
1274 nInodes -= summary.nInodes;
1275 ip += summary.nInodes;
1276 }
1277 free(ip_save);
1278 ip = ip_save = NULL((void *)0);
1279 /* Following fflush is not fclose, because if it was debug mode would not work */
1280 if (OS_SYNC(summaryFile)fsync(summaryFile) == -1) {
1281 Log("Unable to write summary file (errno = %d); %s not salvaged\n", errno(* __error()), dev);
1282 OS_CLOSE(summaryFile)close(summaryFile);
1283 retcode = -1;
1284 goto error;
1285 }
1286 if (canfork && !debug) {
1287 ShowLog = 0;
1288 Exit(0);
1289 }
1290 } else {
1291 if (Wait("Inode summary") == -1) {
1292 OS_CLOSE(summaryFile)close(summaryFile);
1293 Exit(1); /* salvage of this partition aborted */
1294 }
1295 }
1296
1297 st_size = OS_SIZE(summaryFile)ih_size(summaryFile);
1298 osi_Assert(st_size >= 0)(void)((st_size >= 0) || (osi_AssertFailU("st_size >= 0"
, "./../vol/vol-salvage.c", 1298), 0))
;
1299 if (st_size != 0) {
1300 int ret;
1301 salvinfo->inodeSummary = (struct InodeSummary *)malloc(st_size);
1302 osi_Assert(salvinfo->inodeSummary != NULL)(void)((salvinfo->inodeSummary != ((void *)0)) || (osi_AssertFailU
("salvinfo->inodeSummary != NULL", "./../vol/vol-salvage.c"
, 1302), 0))
;
1303 /* For GNU we need to do lseek to get the file pointer moved. */
1304 osi_Assert(OS_SEEK(summaryFile, 0, SEEK_SET) == 0)(void)((lseek(summaryFile, (off_t) (0), 0) == 0) || (osi_AssertFailU
("OS_SEEK(summaryFile, 0, SEEK_SET) == 0", "./../vol/vol-salvage.c"
, 1304), 0))
;
1305 ret = OS_READ(summaryFile, salvinfo->inodeSummary, st_size)read(summaryFile, salvinfo->inodeSummary, st_size);
1306 osi_Assert(ret == st_size)(void)((ret == st_size) || (osi_AssertFailU("ret == st_size",
"./../vol/vol-salvage.c", 1306), 0))
;
1307 }
1308 salvinfo->nVolumesInInodeFile = st_size / sizeof(struct InodeSummary);
1309 for (i = 0; i < salvinfo->nVolumesInInodeFile; i++) {
1310 salvinfo->inodeSummary[i].volSummary = NULL((void *)0);
1311 }
1312 Log("%d nVolumesInInodeFile %lu \n",salvinfo->nVolumesInInodeFile,(unsigned long)st_size);
1313 OS_CLOSE(summaryFile)close(summaryFile);
1314
1315 error:
1316 if (retcode && singleVolumeNumber && !deleted) {
1317 AskError(salvinfo, singleVolumeNumber);
1318 }
1319
1320 return retcode;
1321}
1322
1323/* Comparison routine for volume sort.
1324 This is setup so that a read-write volume comes immediately before
1325 any read-only clones of that volume */
1326int
1327CompareVolumes(const void *_p1, const void *_p2)
1328{
1329 const struct VolumeSummary *p1 = _p1;
1330 const struct VolumeSummary *p2 = _p2;
1331 if (p1->header.parent != p2->header.parent)
1332 return p1->header.parent < p2->header.parent ? -1 : 1;
1333 if (p1->header.id == p1->header.parent) /* p1 is rw volume */
1334 return -1;
1335 if (p2->header.id == p2->header.parent) /* p2 is rw volume */
1336 return 1;
1337 return p1->header.id < p2->header.id ? -1 : 1; /* Both read-only */
1338}
1339
1340/**
1341 * Gleans volumeSummary information by asking the fileserver
1342 *
1343 * @param[in] singleVolumeNumber the volume we're salvaging. 0 if we're
1344 * salvaging a whole partition
1345 *
1346 * @return whether we obtained the volume summary information or not
1347 * @retval 0 success; we obtained the volume summary information
1348 * @retval -1 we raced with a fileserver restart; volume locks and checkout
1349 * must be retried
1350 * @retval 1 we did not get the volume summary information; either the
1351 * fileserver responded with an error, or we are not supposed to
1352 * ask the fileserver for the information (e.g. we are salvaging
1353 * the entire partition or we are not the salvageserver)
1354 *
1355 * @note for non-DAFS, always returns 1
1356 */
1357static int
1358AskVolumeSummary(struct SalvInfo *salvinfo, VolumeId singleVolumeNumber)
1359{
1360 afs_int32 code = 1;
1361#if defined(FSSYNC_BUILD_CLIENT1) && defined(AFS_DEMAND_ATTACH_FS1)
1362 if (programType == salvageServer) {
1363 if (singleVolumeNumber) {
1364 FSSYNC_VGQry_response_t q_res;
1365 SYNC_response res;
1366 struct VolumeSummary *vsp;
1367 int i;
1368 struct VolumeDiskHeader diskHdr;
1369
1370 memset(&res, 0, sizeof(res));
1371
1372 code = FSYNC_VGCQuery(salvinfo->fileSysPartition->name, singleVolumeNumber, &q_res, &res);
1373
1374 /*
1375 * We must wait for the partition to finish scanning before
1376 * can continue, since we will not know if we got the entire
1377 * VG membership unless the partition is fully scanned.
1378 * We could, in theory, just scan the partition ourselves if
1379 * the VG cache is not ready, but we would be doing the exact
1380 * same scan the fileserver is doing; it will almost always
1381 * be faster to wait for the fileserver. The only exceptions
1382 * are if the partition does not take very long to scan, and
1383 * in that case it's fast either way, so who cares?
1384 */
1385 if (code == SYNC_FAILED && res.hdr.reason == FSYNC_PART_SCANNING) {
1386 Log("waiting for fileserver to finish scanning partition %s...\n",
1387 salvinfo->fileSysPartition->name);
1388
1389 for (i = 1; code == SYNC_FAILED && res.hdr.reason == FSYNC_PART_SCANNING; i++) {
1390 /* linearly ramp up from 1 to 10 seconds; nothing fancy,
1391 * just so small partitions don't need to wait over 10
1392 * seconds every time, and large partitions are generally
1393 * polled only once every ten seconds. */
1394 sleep((i > 10) ? (i = 10) : i);
1395
1396 code = FSYNC_VGCQuery(salvinfo->fileSysPartition->name, singleVolumeNumber, &q_res, &res);
1397 }
1398 }
1399
1400 if (code == SYNC_FAILED && res.hdr.reason == FSYNC_UNKNOWN_VOLID) {
1401 /* This can happen if there's no header for the volume
1402 * we're salvaging, or no headers exist for the VG (if
1403 * we're salvaging an RW). Act as if we got a response
1404 * with no VG members. The headers may be created during
1405 * salvaging, if there are inodes in this VG. */
1406 code = 0;
1407 memset(&q_res, 0, sizeof(q_res));
1408 q_res.rw = singleVolumeNumber;
1409 }
1410
1411 if (code) {
1412 Log("fileserver refused VGCQuery request for volume %lu on "
1413 "partition %s, code %ld reason %ld\n",
1414 afs_printable_uint32_lu(singleVolumeNumber),
1415 salvinfo->fileSysPartition->name,
1416 afs_printable_int32_ld(code),
1417 afs_printable_int32_ld(res.hdr.reason));
1418 goto done;
1419 }
1420
1421 if (q_res.rw != singleVolumeNumber) {
1422 Log("fileserver requested salvage of clone %lu; scheduling salvage of volume group %lu...\n",
1423 afs_printable_uint32_lu(singleVolumeNumber),
1424 afs_printable_uint32_lu(q_res.rw));
1425#ifdef SALVSYNC_BUILD_CLIENT1
1426 if (SALVSYNC_LinkVolume(q_res.rw,
1427 singleVolumeNumber,
1428 salvinfo->fileSysPartition->name,
1429 NULL((void *)0)) != SYNC_OK) {
1430 Log("schedule request failed\n");
1431 }
1432#endif /* SALVSYNC_BUILD_CLIENT */
1433 Exit(SALSRV_EXIT_VOLGROUP_LINK10);
1434 }
1435
1436 salvinfo->volumeSummaryp = calloc(VOL_VG_MAX_VOLS20, sizeof(struct VolumeSummary));
1437 osi_Assert(salvinfo->volumeSummaryp != NULL)(void)((salvinfo->volumeSummaryp != ((void *)0)) || (osi_AssertFailU
("salvinfo->volumeSummaryp != NULL", "./../vol/vol-salvage.c"
, 1437), 0))
;
1438
1439 salvinfo->nVolumes = 0;
1440 vsp = salvinfo->volumeSummaryp;
1441
1442 for (i = 0; i < VOL_VG_MAX_VOLS20; i++) {
1443 char name[VMAXPATHLEN64];
1444
1445 if (!q_res.children[i]) {
1446 continue;
1447 }
1448
1449 /* AskOffline for singleVolumeNumber was called much earlier */
1450 if (q_res.children[i] != singleVolumeNumber) {
1451 AskOffline(salvinfo, q_res.children[i]);
1452 if (LockVolume(salvinfo, q_res.children[i])) {
1453 /* need to retry */
1454 return -1;
1455 }
1456 }
1457
1458 code = VReadVolumeDiskHeader(q_res.children[i], salvinfo->fileSysPartition, &diskHdr);
1459 if (code) {
1460 Log("Cannot read header for %lu; trying to salvage group anyway\n",
1461 afs_printable_uint32_lu(q_res.children[i]));
1462 code = 0;
1463 continue;
1464 }
1465
1466 DiskToVolumeHeader(&vsp->header, &diskHdr);
1467 VolumeExternalName_r(q_res.children[i], name, sizeof(name));
1468 vsp->fileName = ToString(name);
1469 salvinfo->nVolumes++;
1470 vsp++;
1471 }
1472
1473 qsort(salvinfo->volumeSummaryp, salvinfo->nVolumes, sizeof(struct VolumeSummary),
1474 CompareVolumes);
1475 }
1476 done:
1477 if (code) {
1478 Log("Cannot get volume summary from fileserver; falling back to scanning "
1479 "entire partition\n");
1480 }
1481 }
1482#endif /* FSSYNC_BUILD_CLIENT && AFS_DEMAND_ATTACH_FS */
1483 return code;
1484}
1485
1486/**
1487 * count how many volume headers are found by VWalkVolumeHeaders.
1488 *
1489 * @param[in] dp the disk partition (unused)
1490 * @param[in] name full path to the .vol header (unused)
1491 * @param[in] hdr the header data (unused)
1492 * @param[in] last whether this is the last try or not (unused)
1493 * @param[in] rock actually an afs_int32*; the running count of how many
1494 * volumes we have found
1495 *
1496 * @retval 0 always
1497 */
1498static int
1499CountHeader(struct DiskPartition64 *dp, const char *name,
1500 struct VolumeDiskHeader *hdr, int last, void *rock)
1501{
1502 afs_int32 *nvols = (afs_int32 *)rock;
1503 (*nvols)++;
1504 return 0;
1505}
1506
1507/**
1508 * parameters to pass to the VWalkVolumeHeaders callbacks when recording volume
1509 * data.
1510 */
1511struct SalvageScanParams {
1512 VolumeId singleVolumeNumber; /**< 0 for a partition-salvage, otherwise the
1513 * vol id of the VG we're salvaging */
1514 struct VolumeSummary *vsp; /**< ptr to the current volume summary object
1515 * we're filling in */
1516 afs_int32 nVolumes; /**< # of vols we've encountered */
1517 afs_int32 totalVolumes; /**< max # of vols we should encounter (the
1518 * # of vols we've alloc'd memory for) */
1519 int retry; /**< do we need to retry vol lock/checkout? */
1520 struct SalvInfo *salvinfo; /**< salvage job info */
1521};
1522
1523/**
1524 * records volume summary info found from VWalkVolumeHeaders.
1525 *
1526 * Found volumes are also taken offline if they are in the specific volume
1527 * group we are looking for.
1528 *
1529 * @param[in] dp the disk partition
1530 * @param[in] name full path to the .vol header
1531 * @param[in] hdr the header data
1532 * @param[in] last 1 if this is the last try to read the header, 0 otherwise
1533 * @param[in] rock actually a struct SalvageScanParams*, containing the
1534 * information needed to record the volume summary data
1535 *
1536 * @return operation status
1537 * @retval 0 success
1538 * @retval -1 volume locking raced with fileserver restart; checking out
1539 * and locking volumes needs to be retried
1540 * @retval 1 volume header is mis-named and should be deleted
1541 */
1542static int
1543RecordHeader(struct DiskPartition64 *dp, const char *name,
1544 struct VolumeDiskHeader *hdr, int last, void *rock)
1545{
1546 char nameShouldBe[64];
1547 struct SalvageScanParams *params;
1548 struct VolumeSummary summary;
1549 VolumeId singleVolumeNumber;
1550 struct SalvInfo *salvinfo;
1551
1552 params = (struct SalvageScanParams *)rock;
1553
1554 memset(&summary, 0, sizeof(summary));
1555
1556 singleVolumeNumber = params->singleVolumeNumber;
1557 salvinfo = params->salvinfo;
1558
1559 DiskToVolumeHeader(&summary.header, hdr);
1560
1561 if (singleVolumeNumber && summary.header.id == singleVolumeNumber
1562 && summary.header.parent != singleVolumeNumber) {
1563
1564 if (programType == salvageServer) {
1565#ifdef SALVSYNC_BUILD_CLIENT1
1566 Log("fileserver requested salvage of clone %u; scheduling salvage of volume group %u...\n",
1567 summary.header.id, summary.header.parent);
1568 if (SALVSYNC_LinkVolume(summary.header.parent,
1569 summary.header.id,
1570 dp->name,
1571 NULL((void *)0)) != SYNC_OK) {
1572 Log("schedule request failed\n");
1573 }
1574#endif
1575 Exit(SALSRV_EXIT_VOLGROUP_LINK10);
1576
1577 } else {
1578 Log("%u is a read-only volume; not salvaged\n",
1579 singleVolumeNumber);
1580 Exit(1);
1581 }
1582 }
1583
1584 if (!singleVolumeNumber || summary.header.id == singleVolumeNumber
1585 || summary.header.parent == singleVolumeNumber) {
1586
1587 /* check if the header file is incorrectly named */
1588 int badname = 0;
1589 const char *base = strrchr(name, OS_DIRSEPC'/');
1590 if (base) {
1591 base++;
1592 } else {
1593 base = name;
1594 }
1595
1596 snprintf(nameShouldBe, sizeof nameShouldBe,
1597 VFORMAT"V%010lu.vol", afs_printable_uint32_lu(summary.header.id));
1598
1599
1600 if (strcmp(nameShouldBe, base)) {
1601 /* .vol file has wrong name; retry/delete */
1602 badname = 1;
1603 }
1604
1605 if (!badname || last) {
1606 /* only offline the volume if the header is good, or if this is
1607 * the last try looking at it; avoid AskOffline'ing the same vol
1608 * multiple times */
1609
1610 if (singleVolumeNumber
1611 && summary.header.id != singleVolumeNumber) {
1612 /* don't offline singleVolumeNumber; we already did that
1613 * earlier */
1614
1615 AskOffline(salvinfo, summary.header.id);
1616
1617#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
1618 if (!badname) {
1619 /* don't lock the volume if the header is bad, since we're
1620 * about to delete it anyway. */
1621 if (LockVolume(salvinfo, summary.header.id)) {
1622 params->retry = 1;
1623 return -1;
1624 }
1625 }
1626#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
1627 }
1628 }
1629 if (badname) {
1630 if (last && !Showmode) {
1631 Log("Volume header file %s is incorrectly named (should be %s "
1632 "not %s); %sdeleted (it will be recreated later, if "
1633 "necessary)\n", name, nameShouldBe, base,
1634 (Testing ? "it would have been " : ""));
1635 }
1636 return 1;
1637 }
1638
1639 summary.fileName = ToString(base);
1640 params->nVolumes++;
1641
1642 if (params->nVolumes > params->totalVolumes) {
1643 /* We found more volumes than we found on the first partition walk;
1644 * apparently something created a volume while we were
1645 * partition-salvaging, or we found more than 20 vols when salvaging a
1646 * particular volume. Abort if we detect this, since other programs
1647 * supposed to not touch the partition while it is partition-salvaging,
1648 * and we shouldn't find more than 20 vols in a VG.
1649 */
1650 Abort("Found %ld vol headers, but should have found at most %ld! "
1651 "Make sure the volserver/fileserver are not running at the "
1652 "same time as a partition salvage\n",
1653 afs_printable_int32_ld(params->nVolumes),
1654 afs_printable_int32_ld(params->totalVolumes));
1655 }
1656
1657 memcpy(params->vsp, &summary, sizeof(summary));
1658 params->vsp++;
1659 }
1660
1661 return 0;
1662}
1663
1664/**
1665 * possibly unlinks bad volume headers found from VWalkVolumeHeaders.
1666 *
1667 * If the header could not be read in at all, the header is always unlinked.
1668 * If instead RecordHeader said the header was bad (that is, the header file
1669 * is mis-named), we only unlink if we are doing a partition salvage, as
1670 * opposed to salvaging a specific volume group.
1671 *
1672 * @param[in] dp the disk partition
1673 * @param[in] name full path to the .vol header
1674 * @param[in] hdr header data, or NULL if the header could not be read
1675 * @param[in] rock actually a struct SalvageScanParams*, with some information
1676 * about the scan
1677 */
1678static void
1679UnlinkHeader(struct DiskPartition64 *dp, const char *name,
1680 struct VolumeDiskHeader *hdr, void *rock)
1681{
1682 struct SalvageScanParams *params;
1683 int dounlink = 0;
1684
1685 params = (struct SalvageScanParams *)rock;
1686
1687 if (!hdr) {
1688 /* no header; header is too bogus to read in at all */
1689 if (!Showmode) {
1690 Log("%s is not a legitimate volume header file; %sdeleted\n", name, (Testing ? "it would have been " : ""));
1691 }
1692 if (!Testing) {
1693 dounlink = 1;
1694 }
1695
1696 } else if (!params->singleVolumeNumber) {
1697 /* We were able to read in a header, but RecordHeader said something
1698 * was wrong with it. We only unlink those if we are doing a partition
1699 * salvage. */
1700 if (!Testing) {
1701 dounlink = 1;
1702 }
1703 }
1704
1705 if (dounlink && unlink(name)) {
1706 Log("Error %d while trying to unlink %s\n", errno(* __error()), name);
1707 }
1708}
1709
1710/**
1711 * Populates salvinfo->volumeSummaryp with volume summary information, either by asking
1712 * the fileserver for VG information, or by scanning the /vicepX partition.
1713 *
1714 * @param[in] singleVolumeNumber the volume ID of the single volume group we
1715 * are salvaging, or 0 if this is a partition
1716 * salvage
1717 *
1718 * @return operation status
1719 * @retval 0 success
1720 * @retval -1 we raced with a fileserver restart; checking out and locking
1721 * volumes must be retried
1722 */
1723int
1724GetVolumeSummary(struct SalvInfo *salvinfo, VolumeId singleVolumeNumber)
1725{
1726 afs_int32 nvols = 0;
1727 struct SalvageScanParams params;
1728 int code;
1729
1730 code = AskVolumeSummary(salvinfo, singleVolumeNumber);
1731 if (code == 0) {
1732 /* we successfully got the vol information from the fileserver; no
1733 * need to scan the partition */
1734 return 0;
1735 }
1736 if (code < 0) {
1737 /* we need to retry volume checkout */
1738 return code;
1739 }
1740
1741 if (!singleVolumeNumber) {
1742 /* Count how many volumes we have in /vicepX */
1743 code = VWalkVolumeHeaders(salvinfo->fileSysPartition, salvinfo->fileSysPath, CountHeader,
1744 NULL((void *)0), &nvols);
1745 if (code < 0) {
1746 Abort("Can't read directory %s; not salvaged\n", salvinfo->fileSysPath);
1747 }
1748 if (!nvols)
1749 nvols = 1;
1750 } else {
1751 nvols = VOL_VG_MAX_VOLS20;
1752 }
1753
1754 salvinfo->volumeSummaryp = calloc(nvols, sizeof(struct VolumeSummary));
1755 osi_Assert(salvinfo->volumeSummaryp != NULL)(void)((salvinfo->volumeSummaryp != ((void *)0)) || (osi_AssertFailU
("salvinfo->volumeSummaryp != NULL", "./../vol/vol-salvage.c"
, 1755), 0))
;
1756
1757 params.singleVolumeNumber = singleVolumeNumber;
1758 params.vsp = salvinfo->volumeSummaryp;
1759 params.nVolumes = 0;
1760 params.totalVolumes = nvols;
1761 params.retry = 0;
1762 params.salvinfo = salvinfo;
1763
1764 /* walk the partition directory of volume headers and record the info
1765 * about them; unlinking invalid headers */
1766 code = VWalkVolumeHeaders(salvinfo->fileSysPartition, salvinfo->fileSysPath, RecordHeader,
1767 UnlinkHeader, &params);
1768 if (params.retry) {
1769 /* we apparently need to retry checking-out/locking volumes */
1770 return -1;
1771 }
1772 if (code < 0) {
1773 Abort("Failed to get volume header summary\n");
1774 }
1775 salvinfo->nVolumes = params.nVolumes;
1776
1777 qsort(salvinfo->volumeSummaryp, salvinfo->nVolumes, sizeof(struct VolumeSummary),
1778 CompareVolumes);
1779
1780 return 0;
1781}
1782
1783/* Find the link table. This should be associated with the RW volume or, if
1784 * a RO only site, then the RO volume. For now, be cautious and hunt carefully.
1785 */
1786Inode
1787FindLinkHandle(struct InodeSummary *isp, int nVols,
1788 struct ViceInodeInfo *allInodes)
1789{
1790 int i, j;
1791 struct ViceInodeInfo *ip;
1792
1793 for (i = 0; i < nVols; i++) {
1794 ip = allInodes + isp[i].index;
1795 for (j = 0; j < isp[i].nSpecialInodes; j++) {
1796 if (ip[j].u.special.type == VI_LINKTABLE6)
1797 return ip[j].inodeNumber;
1798 }
1799 }
1800 return (Inode) - 1;
1801}
1802
1803int
1804CreateLinkTable(struct SalvInfo *salvinfo, struct InodeSummary *isp, Inode ino)
1805{
1806 struct versionStamp version;
1807 FdHandle_t *fdP;
1808
1809 if (!VALID_INO(ino)((ino) != (Inode)-1 && (ino) != (Inode)0))
1810 ino =
1811 IH_CREATE(NULL, salvinfo->fileSysDevice, salvinfo->fileSysPath, 0, isp->volumeId,namei_icreate(((void *)0), salvinfo->fileSysPath, isp->
volumeId, 0xffffffff, 6, isp->RWvolumeId)
1812 INODESPECIAL, VI_LINKTABLE, isp->RWvolumeId)namei_icreate(((void *)0), salvinfo->fileSysPath, isp->
volumeId, 0xffffffff, 6, isp->RWvolumeId)
;
1813 if (!VALID_INO(ino)((ino) != (Inode)-1 && (ino) != (Inode)0))
1814 Abort
1815 ("Unable to allocate link table inode for volume %u (error = %d)\n",
1816 isp->RWvolumeId, errno(* __error()));
1817 IH_INIT(salvinfo->VGLinkH, salvinfo->fileSysDevice, isp->RWvolumeId, ino)((salvinfo->VGLinkH) = ih_init((salvinfo->fileSysDevice
), (isp->RWvolumeId), (ino)))
;
1818 fdP = IH_OPEN(salvinfo->VGLinkH)ih_open(salvinfo->VGLinkH);
1819 if (fdP == NULL((void *)0))
1820 Abort("Can't open link table for volume %u (error = %d)\n",
1821 isp->RWvolumeId, errno(* __error()));
1822
1823 if (FDH_TRUNC(fdP, sizeof(version) + sizeof(short))ftruncate((fdP)->fd_fd, (off_t) (sizeof(version) + sizeof(
short)))
< 0)
1824 Abort("Can't truncate link table for volume %u (error = %d)\n",
1825 isp->RWvolumeId, errno(* __error()));
1826
1827 version.magic = LINKTABLEMAGIC0x99877712;
1828 version.version = LINKTABLEVERSION1;
1829
1830 if (FDH_PWRITE(fdP, (char *)&version, sizeof(version), 0)pwrite((fdP)->fd_fd, (char *)&version, sizeof(version)
, 0)
1831 != sizeof(version))
1832 Abort("Can't truncate link table for volume %u (error = %d)\n",
1833 isp->RWvolumeId, errno(* __error()));
1834
1835 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
1836
1837 /* If the volume summary exits (i.e., the V*.vol header file exists),
1838 * then set this inode there as well.
1839 */
1840 if (isp->volSummary)
1841 isp->volSummary->header.linkTable = ino;
1842
1843 return 0;
1844}
1845
1846#ifdef AFS_NT40_ENV
1847void *
1848nt_SVG(void *arg)
1849{
1850 SVGParms_t *parms = (SVGParms_t *) arg;
1851 DoSalvageVolumeGroup(parms->svgp_salvinfo, parms->svgp_inodeSummaryp, parms->svgp_count);
1852 return NULL((void *)0);
1853}
1854
1855void
1856nt_SalvageVolumeGroup(struct SalvInfo *salvinfo, struct InodeSummary *isp, int nVols)
1857{
1858 pthread_t tid;
1859 pthread_attr_t tattr;
1860 int code;
1861 SVGParms_t parms;
1862
1863 /* Initialize per volume global variables, even if later code does so */
1864 salvinfo->VolumeChanged = 0;
1865 salvinfo->VGLinkH = NULL((void *)0);
1866 salvinfo->VGLinkH_cnt = 0;
1867 memset(&salvinfo->VolInfo, 0, sizeof(salvinfo->VolInfo));
1868
1869 parms.svgp_inodeSummaryp = isp;
1870 parms.svgp_count = nVols;
1871 parms.svgp_salvinfo = salvinfo;
1872 code = pthread_attr_init(&tattr);
1873 if (code) {
1874 Log("Failed to salvage volume group %u: pthread_attr_init()\n",
1875 isp->RWvolumeId);
1876 return;
1877 }
1878 code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE0);
1879 if (code) {
1880 Log("Failed to salvage volume group %u: pthread_attr_setdetachstate()\n", isp->RWvolumeId);
1881 return;
1882 }
1883 code = pthread_create(&tid, &tattr, nt_SVG, &parms);
1884 if (code) {
1885 Log("Failed to create thread to salvage volume group %u\n",
1886 isp->RWvolumeId);
1887 return;
1888 }
1889 (void)pthread_join(tid, NULL((void *)0));
1890}
1891#endif /* AFS_NT40_ENV */
1892
1893void
1894DoSalvageVolumeGroup(struct SalvInfo *salvinfo, struct InodeSummary *isp, int nVols)
1895{
1896 struct ViceInodeInfo *inodes, *allInodes, *ip;
1897 int i, totalInodes, size, salvageTo;
1898 int haveRWvolume;
1899 int check;
1900 Inode ino;
1901 int dec_VGLinkH = 0;
1902 int VGLinkH_p1 =0;
1903 FdHandle_t *fdP = NULL((void *)0);
1904
1905 salvinfo->VGLinkH_cnt = 0;
1906 haveRWvolume = (isp->volumeId == isp->RWvolumeId
1907 && isp->nSpecialInodes > 0);
1908 if ((!ShowMounts) || (ShowMounts && !haveRWvolume)) {
1
Taking true branch
1909 if (!ForceSalvage && QuickCheck(salvinfo, isp, nVols))
2
Taking false branch
1910 return;
1911 }
1912 if (ShowMounts && !haveRWvolume)
3
Taking false branch
1913 return;
1914 if (canfork && !debug && Fork() != 0) {
4
Taking false branch
1915 (void)Wait("Salvage volume group");
1916 return;
1917 }
1918 for (i = 0, totalInodes = 0; i < nVols; i++)
5
Loop condition is false. Execution continues on line 1920
1919 totalInodes += isp[i].nInodes;
1920 size = totalInodes * sizeof(struct ViceInodeInfo);
1921 inodes = (struct ViceInodeInfo *)malloc(size);
6
Call to 'malloc' has an allocation size of 0 bytes
1922 allInodes = inodes - isp->index; /* this would the base of all the inodes
1923 * for the partition, if all the inodes
1924 * had been read into memory */
1925 osi_Assert(OS_SEEK(void)((lseek(salvinfo->inodeFd, (off_t) (isp->index * sizeof
(struct ViceInodeInfo)), 0) != -1) || (osi_AssertFailU("OS_SEEK (salvinfo->inodeFd, isp->index * sizeof(struct ViceInodeInfo), SEEK_SET) != -1"
, "./../vol/vol-salvage.c", 1927), 0))
1926 (salvinfo->inodeFd, isp->index * sizeof(struct ViceInodeInfo),(void)((lseek(salvinfo->inodeFd, (off_t) (isp->index * sizeof
(struct ViceInodeInfo)), 0) != -1) || (osi_AssertFailU("OS_SEEK (salvinfo->inodeFd, isp->index * sizeof(struct ViceInodeInfo), SEEK_SET) != -1"
, "./../vol/vol-salvage.c", 1927), 0))
1927 SEEK_SET) != -1)(void)((lseek(salvinfo->inodeFd, (off_t) (isp->index * sizeof
(struct ViceInodeInfo)), 0) != -1) || (osi_AssertFailU("OS_SEEK (salvinfo->inodeFd, isp->index * sizeof(struct ViceInodeInfo), SEEK_SET) != -1"
, "./../vol/vol-salvage.c", 1927), 0))
;
1928 osi_Assert(OS_READ(salvinfo->inodeFd, inodes, size) == size)(void)((read(salvinfo->inodeFd, inodes, size) == size) || (
osi_AssertFailU("OS_READ(salvinfo->inodeFd, inodes, size) == size"
, "./../vol/vol-salvage.c", 1928), 0))
;
1929
1930 /* Don't try to salvage a read write volume if there isn't one on this
1931 * partition */
1932 salvageTo = haveRWvolume ? 0 : 1;
1933
1934#ifdef AFS_NAMEI_ENV1
1935 ino = FindLinkHandle(isp, nVols, allInodes);
1936 if (VALID_INO(ino)((ino) != (Inode)-1 && (ino) != (Inode)0)) {
1937 IH_INIT(salvinfo->VGLinkH, salvinfo->fileSysDevice, isp->RWvolumeId, ino)((salvinfo->VGLinkH) = ih_init((salvinfo->fileSysDevice
), (isp->RWvolumeId), (ino)))
;
1938 fdP = IH_OPEN(salvinfo->VGLinkH)ih_open(salvinfo->VGLinkH);
1939 }
1940 if (VALID_INO(ino)((ino) != (Inode)-1 && (ino) != (Inode)0) && fdP != NULL((void *)0)) {
1941 struct versionStamp header;
1942 afs_sfsize_t nBytes;
1943
1944 nBytes = FDH_PREAD(fdP, (char *)&header, sizeof(struct versionStamp), 0)pread((fdP)->fd_fd, (char *)&header, sizeof(struct versionStamp
), 0)
;
1945 if (nBytes != sizeof(struct versionStamp)
1946 || header.magic != LINKTABLEMAGIC0x99877712) {
1947 Log("Bad linktable header for volume %u.\n", isp->RWvolumeId);
1948 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
1949 fdP = NULL((void *)0);
1950 }
1951 }
1952 if (!VALID_INO(ino)((ino) != (Inode)-1 && (ino) != (Inode)0) || fdP == NULL((void *)0)) {
1953 Log("%s link table for volume %u.\n",
1954 Testing ? "Would have recreated" : "Recreating", isp->RWvolumeId);
1955 if (Testing) {
1956 IH_INIT(salvinfo->VGLinkH, salvinfo->fileSysDevice, -1, -1)((salvinfo->VGLinkH) = ih_init((salvinfo->fileSysDevice
), (-1), (-1)))
;
1957 } else {
1958 int i, j;
1959 struct ViceInodeInfo *ip;
1960 CreateLinkTable(salvinfo, isp, ino);
1961 fdP = IH_OPEN(salvinfo->VGLinkH)ih_open(salvinfo->VGLinkH);
1962 /* Sync fake 1 link counts to the link table, now that it exists */
1963 if (fdP) {
1964 for (i = 0; i < nVols; i++) {
1965 ip = allInodes + isp[i].index;
1966 for (j = isp[i].nSpecialInodes; j < isp[i].nInodes; j++) {
1967 namei_SetLinkCount(fdP, ip[j].inodeNumber, 1, 1);
1968 }
1969 }
1970 }
1971 }
1972 }
1973 if (fdP)
1974 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
1975#else
1976 IH_INIT(salvinfo->VGLinkH, salvinfo->fileSysDevice, -1, -1)((salvinfo->VGLinkH) = ih_init((salvinfo->fileSysDevice
), (-1), (-1)))
;
1977#endif
1978
1979 /* Salvage in reverse order--read/write volume last; this way any
1980 * Inodes not referenced by the time we salvage the read/write volume
1981 * can be picked up by the read/write volume */
1982 /* ACTUALLY, that's not done right now--the inodes just vanish */
1983 for (i = nVols - 1; i >= salvageTo; i--) {
1984 int rw = (i == 0);
1985 struct InodeSummary *lisp = &isp[i];
1986#ifdef AFS_NAMEI_ENV1
1987 /* If only the RO is present on this partition, the link table
1988 * shows up as a RW volume special file. Need to make sure the
1989 * salvager doesn't try to salvage the non-existent RW.
1990 */
1991 if (rw && nVols > 1 && isp[i].nSpecialInodes == 1) {
1992 /* If this only special inode is the link table, continue */
1993 if (inodes->u.special.type == VI_LINKTABLE6) {
1994 haveRWvolume = 0;
1995 continue;
1996 }
1997 }
1998#endif
1999 if (!Showmode)
2000 Log("%s VOLUME %u%s.\n", rw ? "SALVAGING" : "CHECKING CLONED",
2001 lisp->volumeId, (Testing ? "(READONLY mode)" : ""));
2002 /* Check inodes twice. The second time do things seriously. This
2003 * way the whole RO volume can be deleted, below, if anything goes wrong */
2004 for (check = 1; check >= 0; check--) {
2005 int deleteMe;
2006 if (SalvageVolumeHeaderFile(salvinfo, lisp, allInodes, rw, check, &deleteMe)
2007 == -1) {
2008 MaybeZapVolume(salvinfo, lisp, "Volume header", deleteMe, check);
2009 if (rw && deleteMe) {
2010 haveRWvolume = 0; /* This will cause its inodes to be deleted--since salvage
2011 * volume won't be called */
2012 break;
2013 }
2014 if (!rw)
2015 break;
2016 }
2017 if (rw && check == 1)
2018 continue;
2019 if (SalvageVnodes(salvinfo, isp, lisp, allInodes, check) == -1) {
2020 MaybeZapVolume(salvinfo, lisp, "Vnode index", 0, check);
2021 break;
2022 }
2023 }
2024 }
2025
2026 /* Fix actual inode counts */
2027 if (!Showmode) {
2028 afs_ino_str_t stmp;
2029 Log("totalInodes %d\n",totalInodes);
2030 for (ip = inodes; totalInodes; ip++, totalInodes--) {
2031 static int TraceBadLinkCounts = 0;
2032#ifdef AFS_NAMEI_ENV1
2033 if (salvinfo->VGLinkH->ih_ino == ip->inodeNumber) {
2034 dec_VGLinkH = ip->linkCount - salvinfo->VGLinkH_cnt;
2035 VGLinkH_p1 = ip->u.param[0];
2036 continue; /* Deal with this last. */
2037 }
2038#endif
2039 if (ip->linkCount != 0 && TraceBadLinkCounts) {
2040 TraceBadLinkCounts--; /* Limit reports, per volume */
2041 Log("#### DEBUG #### Link count incorrect by %d; inode %s, size %llu, p=(%u,%u,%u,%u)\n", ip->linkCount, PrintInode(stmp, ip->inodeNumber), (afs_uintmax_t) ip->byteCount, ip->u.param[0], ip->u.param[1], ip->u.param[2], ip->u.param[3]);
2042 }
2043 while (ip->linkCount > 0) {
2044 /* below used to assert, not break */
2045 if (!Testing) {
2046 if (IH_DEC(salvinfo->VGLinkH, ip->inodeNumber, ip->u.param[0])namei_dec(salvinfo->VGLinkH, ip->inodeNumber, ip->u.
param[0])
) {
2047 Log("idec failed. inode %s errno %d\n",
2048 PrintInode(stmp, ip->inodeNumber), errno(* __error()));
2049 break;
2050 }
2051 }
2052 ip->linkCount--;
2053 }
2054 while (ip->linkCount < 0) {
2055 /* these used to be asserts */
2056 if (!Testing) {
2057 if (IH_INC(salvinfo->VGLinkH, ip->inodeNumber, ip->u.param[0])namei_inc(salvinfo->VGLinkH, ip->inodeNumber, ip->u.
param[0])
) {
2058 Log("iinc failed. inode %s errno %d\n",
2059 PrintInode(stmp, ip->inodeNumber), errno(* __error()));
2060 break;
2061 }
2062 }
2063 ip->linkCount++;
2064 }
2065 }
2066#ifdef AFS_NAMEI_ENV1
2067 while (dec_VGLinkH > 0) {
2068 if (IH_DEC(salvinfo->VGLinkH, salvinfo->VGLinkH->ih_ino, VGLinkH_p1)namei_dec(salvinfo->VGLinkH, salvinfo->VGLinkH->ih_ino
, VGLinkH_p1)
< 0) {
2069 Log("idec failed on link table, errno = %d\n", errno(* __error()));
2070 }
2071 dec_VGLinkH--;
2072 }
2073 while (dec_VGLinkH < 0) {
2074 if (IH_INC(salvinfo->VGLinkH, salvinfo->VGLinkH->ih_ino, VGLinkH_p1)namei_inc(salvinfo->VGLinkH, salvinfo->VGLinkH->ih_ino
, VGLinkH_p1)
< 0) {
2075 Log("iinc failed on link table, errno = %d\n", errno(* __error()));
2076 }
2077 dec_VGLinkH++;
2078 }
2079#endif
2080 }
2081 free(inodes);
2082 /* Directory consistency checks on the rw volume */
2083 if (haveRWvolume)
2084 SalvageVolume(salvinfo, isp, salvinfo->VGLinkH);
2085 IH_RELEASE(salvinfo->VGLinkH)(ih_release(salvinfo->VGLinkH), (salvinfo->VGLinkH)=((void
*)0), 0)
;
2086
2087 if (canfork && !debug) {
2088 ShowLog = 0;
2089 Exit(0);
2090 }
2091}
2092
2093int
2094QuickCheck(struct SalvInfo *salvinfo, struct InodeSummary *isp, int nVols)
2095{
2096 /* Check headers BEFORE forking */
2097 int i;
2098 IHandle_t *h;
2099
2100 for (i = 0; i < nVols; i++) {
2101 struct VolumeSummary *vs = isp[i].volSummary;
2102 VolumeDiskData volHeader;
2103 if (!vs) {
2104 /* Don't salvage just because phantom rw volume is there... */
2105 /* (If a read-only volume exists, read/write inodes must also exist) */
2106 if (i == 0 && isp->nSpecialInodes == 0 && nVols > 1)
2107 continue;
2108 return 0;
2109 }
2110 IH_INIT(h, salvinfo->fileSysDevice, vs->header.parent, vs->header.volumeInfo)((h) = ih_init((salvinfo->fileSysDevice), (vs->header.parent
), (vs->header.volumeInfo)))
;
2111 if (IH_IREAD(h, 0, (char *)&volHeader, sizeof(volHeader))namei_iread(h, 0, (char *)&volHeader, sizeof(volHeader))
2112 == sizeof(volHeader)
2113 && volHeader.stamp.magic == VOLUMEINFOMAGIC((bit32)0x78a1b2c5)
2114 && volHeader.dontSalvage == DONT_SALVAGE0xE5
2115 && volHeader.needsSalvaged == 0 && volHeader.destroyMe == 0) {
2116 if (volHeader.inUse != 0) {
2117 volHeader.inUse = 0;
2118 volHeader.inService = 1;
2119 if (!Testing) {
2120 if (IH_IWRITE(h, 0, (char *)&volHeader, sizeof(volHeader))namei_iwrite(h, 0, (char *)&volHeader, sizeof(volHeader))
2121 != sizeof(volHeader)) {
2122 IH_RELEASE(h)(ih_release(h), (h)=((void *)0), 0);
2123 return 0;
2124 }
2125 }
2126 }
2127 IH_RELEASE(h)(ih_release(h), (h)=((void *)0), 0);
2128 } else {
2129 IH_RELEASE(h)(ih_release(h), (h)=((void *)0), 0);
2130 return 0;
2131 }
2132 }
2133 return 1;
2134}
2135
2136
2137/* SalvageVolumeHeaderFile
2138 *
2139 * Salvage the top level V*.vol header file. Make sure the special files
2140 * exist and that there are no duplicates.
2141 *
2142 * Calls SalvageHeader for each possible type of volume special file.
2143 */
2144
2145int
2146SalvageVolumeHeaderFile(struct SalvInfo *salvinfo, struct InodeSummary *isp,
2147 struct ViceInodeInfo *inodes, int RW,
2148 int check, int *deleteMe)
2149{
2150 int i;
2151 struct ViceInodeInfo *ip;
2152 int allinodesobsolete = 1;
2153 struct VolumeDiskHeader diskHeader;
2154 afs_int32 (*writefunc)(VolumeDiskHeader_t *, struct DiskPartition64 *) = NULL((void *)0);
2155 int *skip;
2156 struct VolumeHeader tempHeader;
2157 struct afs_inode_info stuff[MAXINODETYPE6];
2158
2159 /* keeps track of special inodes that are probably 'good'; they are
2160 * referenced in the vol header, and are included in the given inodes
2161 * array */
2162 struct {
2163 int valid;
2164 Inode inode;
2165 } goodspecial[MAXINODETYPE6];
2166
2167 if (deleteMe)
2168 *deleteMe = 0;
2169
2170 memset(goodspecial, 0, sizeof(goodspecial));
2171
2172 skip = malloc(isp->nSpecialInodes * sizeof(*skip));
2173 if (skip) {
2174 memset(skip, 0, isp->nSpecialInodes * sizeof(*skip));
2175 } else {
2176 Log("cannot allocate memory for inode skip array when salvaging "
2177 "volume %lu; not performing duplicate special inode recovery\n",
2178 afs_printable_uint32_lu(isp->volumeId));
2179 /* still try to perform the salvage; the skip array only does anything
2180 * if we detect duplicate special inodes */
2181 }
2182
2183 init_inode_info(&tempHeader, stuff);
2184
2185 /*
2186 * First, look at the special inodes and see if any are referenced by
2187 * the existing volume header. If we find duplicate special inodes, we
2188 * can use this information to use the referenced inode (it's more
2189 * likely to be the 'good' one), and throw away the duplicates.
2190 */
2191 if (isp->volSummary && skip) {
2192 /* use tempHeader, so we can use the stuff[] array to easily index
2193 * into the isp->volSummary special inodes */
2194 memcpy(&tempHeader, &isp->volSummary->header, sizeof(struct VolumeHeader));
2195
2196 for (i = 0; i < isp->nSpecialInodes; i++) {
2197 ip = &inodes[isp->index + i];
2198 if (ip->u.special.type <= 0 || ip->u.special.type > MAXINODETYPE6) {
2199 /* will get taken care of in a later loop */
2200 continue;
2201 }
2202 if (ip->inodeNumber == *(stuff[ip->u.special.type - 1].inode)) {
2203 goodspecial[ip->u.special.type-1].valid = 1;
2204 goodspecial[ip->u.special.type-1].inode = ip->inodeNumber;
2205 }
2206 }
2207 }
2208
2209 memset(&tempHeader, 0, sizeof(tempHeader));
2210 tempHeader.stamp.magic = VOLUMEHEADERMAGIC((bit32)0x88a1bb3c);
2211 tempHeader.stamp.version = VOLUMEHEADERVERSION1;
2212 tempHeader.id = isp->volumeId;
2213 tempHeader.parent = isp->RWvolumeId;
2214
2215 /* Check for duplicates (inodes are sorted by type field) */
2216 for (i = 0; i < isp->nSpecialInodes - 1; i++) {
2217 ip = &inodes[isp->index + i];
2218 if (ip->u.special.type == (ip + 1)->u.special.type) {
2219 afs_ino_str_t stmp1, stmp2;
2220
2221 if (ip->u.special.type <= 0 || ip->u.special.type > MAXINODETYPE6) {
2222 /* Will be caught in the loop below */
2223 continue;
2224 }
2225 if (!Showmode) {
2226 Log("Duplicate special %d inodes for volume %u found (%s, %s);\n",
2227 ip->u.special.type, isp->volumeId,
2228 PrintInode(stmp1, ip->inodeNumber),
2229 PrintInode(stmp2, (ip+1)->inodeNumber));
2230 }
2231 if (skip && goodspecial[ip->u.special.type-1].valid) {
2232 Inode gi = goodspecial[ip->u.special.type-1].inode;
2233
2234 if (!Showmode) {
2235 Log("using special inode referenced by vol header (%s)\n",
2236 PrintInode(stmp1, gi));
2237 }
2238
2239 /* the volume header references some special inode of
2240 * this type in the inodes array; are we it? */
2241 if (ip->inodeNumber != gi) {
2242 skip[i] = 1;
2243 } else if ((ip+1)->inodeNumber != gi) {
2244 /* in case this is the last iteration; we need to
2245 * make sure we check ip+1, too */
2246 skip[i+1] = 1;
2247 }
2248 } else {
2249 if (!Showmode)
2250 Log("cannot determine which is correct; salvage of volume %u aborted\n", isp->volumeId);
2251 if (skip) {
2252 free(skip);
2253 }
2254 return -1;
2255 }
2256 }
2257 }
2258 for (i = 0; i < isp->nSpecialInodes; i++) {
2259 afs_ino_str_t stmp;
2260 ip = &inodes[isp->index + i];
2261 if (ip->u.special.type <= 0 || ip->u.special.type > MAXINODETYPE6) {
2262 if (check) {
2263 Log("Rubbish header inode %s of type %d\n",
2264 PrintInode(stmp, ip->inodeNumber),
2265 ip->u.special.type);
2266 if (skip) {
2267 free(skip);
2268 }
2269 return -1;
2270 }
2271 Log("Rubbish header inode %s of type %d; deleted\n",
2272 PrintInode(stmp, ip->inodeNumber),
2273 ip->u.special.type);
2274 } else if (!stuff[ip->u.special.type - 1].obsolete) {
2275 if (skip && skip[i]) {
2276 if (orphans == ORPH_REMOVE1) {
2277 Log("Removing orphan special inode %s of type %d\n",
2278 PrintInode(stmp, ip->inodeNumber), ip->u.special.type);
2279 continue;
2280 } else {
2281 Log("Ignoring orphan special inode %s of type %d\n",
2282 PrintInode(stmp, ip->inodeNumber), ip->u.special.type);
2283 /* fall through to the ip->linkCount--; line below */
2284 }
2285 } else {
2286 *(stuff[ip->u.special.type - 1].inode) = ip->inodeNumber;
2287 allinodesobsolete = 0;
2288 }
2289 if (!check && ip->u.special.type != VI_LINKTABLE6)
2290 ip->linkCount--; /* Keep the inode around */
2291 }
2292 }
2293 if (skip) {
2294 free(skip);
2295 }
2296 skip = NULL((void *)0);
2297
2298 if (allinodesobsolete) {
2299 if (deleteMe)
2300 *deleteMe = 1;
2301 return -1;
2302 }
2303
2304 if (!check)
2305 salvinfo->VGLinkH_cnt++; /* one for every header. */
2306
2307 if (!RW && !check && isp->volSummary) {
2308 ClearROInUseBit(isp->volSummary);
2309 return 0;
2310 }
2311
2312 for (i = 0; i < MAXINODETYPE6; i++) {
2313 if (stuff[i].inodeType == VI_LINKTABLE6) {
2314 /* Gross hack: SalvageHeader does a bcmp on the volume header.
2315 * And we may have recreated the link table earlier, so set the
2316 * RW header as well. The header magic was already checked.
2317 */
2318 if (VALID_INO(salvinfo->VGLinkH->ih_ino)((salvinfo->VGLinkH->ih_ino) != (Inode)-1 && (salvinfo
->VGLinkH->ih_ino) != (Inode)0)
) {
2319 *stuff[i].inode = salvinfo->VGLinkH->ih_ino;
2320 }
2321 continue;
2322 }
2323 if (SalvageHeader(salvinfo, &stuff[i], isp, check, deleteMe) == -1 && check)
2324 return -1;
2325 }
2326
2327 if (isp->volSummary == NULL((void *)0)) {
2328 char path[64];
2329 char headerName[64];
2330 snprintf(headerName, sizeof headerName, VFORMAT"V%010lu.vol",
2331 afs_printable_uint32_lu(isp->volumeId));
2332 snprintf(path, sizeof path, "%s" OS_DIRSEP"/" "%s",
2333 salvinfo->fileSysPath, headerName);
2334 if (check) {
2335 Log("No header file for volume %u\n", isp->volumeId);
2336 return -1;
2337 }
2338 if (!Showmode)
2339 Log("No header file for volume %u; %screating %s\n",
2340 isp->volumeId, (Testing ? "it would have been " : ""),
2341 path);
2342 isp->volSummary = calloc(1, sizeof(struct VolumeSummary));
2343 isp->volSummary->fileName = ToString(headerName);
2344
2345 writefunc = VCreateVolumeDiskHeader;
2346 } else {
2347 char path[64];
2348 char headerName[64];
2349 /* hack: these two fields are obsolete... */
2350 isp->volSummary->header.volumeAcl = 0;
2351 isp->volSummary->header.volumeMountTable = 0;
2352
2353 if (memcmp
2354 (&isp->volSummary->header, &tempHeader,
2355 sizeof(struct VolumeHeader))) {
2356 /* We often remove the name before calling us, so we make a fake one up */
2357 if (isp->volSummary->fileName) {
2358 strcpy(headerName, isp->volSummary->fileName);
2359 } else {
2360 snprintf(headerName, sizeof headerName, VFORMAT"V%010lu.vol",
2361 afs_printable_uint32_lu(isp->volumeId));
2362 isp->volSummary->fileName = ToString(headerName);
2363 }
2364 snprintf(path, sizeof path, "%s" OS_DIRSEP"/" "%s",
2365 salvinfo->fileSysPath, headerName);
2366
2367 Log("Header file %s is damaged or no longer valid%s\n", path,
2368 (check ? "" : "; repairing"));
2369 if (check)
2370 return -1;
2371
2372 writefunc = VWriteVolumeDiskHeader;
2373 }
2374 }
2375 if (writefunc) {
2376 memcpy(&isp->volSummary->header, &tempHeader,
2377 sizeof(struct VolumeHeader));
2378 if (Testing) {
2379 if (!Showmode)
2380 Log("It would have written a new header file for volume %u\n",
2381 isp->volumeId);
2382 } else {
2383 afs_int32 code;
2384 VolumeHeaderToDisk(&diskHeader, &tempHeader);
2385 code = (*writefunc)(&diskHeader, salvinfo->fileSysPartition);
2386 if (code) {
2387 Log("Error %ld writing volume header file for volume %lu\n",
2388 afs_printable_int32_ld(code),
2389 afs_printable_uint32_lu(diskHeader.id));
2390 return -1;
2391 }
2392 }
2393 }
2394 IH_INIT(isp->volSummary->volumeInfoHandle, salvinfo->fileSysDevice, isp->RWvolumeId,((isp->volSummary->volumeInfoHandle) = ih_init((salvinfo
->fileSysDevice), (isp->RWvolumeId), (isp->volSummary
->header.volumeInfo)))
2395 isp->volSummary->header.volumeInfo)((isp->volSummary->volumeInfoHandle) = ih_init((salvinfo
->fileSysDevice), (isp->RWvolumeId), (isp->volSummary
->header.volumeInfo)))
;
2396 return 0;
2397}
2398
2399int
2400SalvageHeader(struct SalvInfo *salvinfo, struct afs_inode_info *sp,
2401 struct InodeSummary *isp, int check, int *deleteMe)
2402{
2403 union {
2404 VolumeDiskData volumeInfo;
2405 struct versionStamp fileHeader;
2406 } header;
2407 IHandle_t *specH;
2408 int recreate = 0;
2409 ssize_t nBytes;
2410 FdHandle_t *fdP;
2411
2412 if (sp->obsolete)
2413 return 0;
2414#ifndef AFS_NAMEI_ENV1
2415 if (sp->inodeType == VI_LINKTABLE6)
2416 return 0; /* header magic was already checked */
2417#endif
2418 if (*(sp->inode) == 0) {
2419 if (check) {
2420 Log("Missing inode in volume header (%s)\n", sp->description);
2421 return -1;
2422 }
2423 if (!Showmode)
2424 Log("Missing inode in volume header (%s); %s\n", sp->description,
2425 (Testing ? "it would have recreated it" : "recreating"));
2426 if (!Testing) {
2427 *(sp->inode) =
2428 IH_CREATE(NULL, salvinfo->fileSysDevice, salvinfo->fileSysPath, 0, isp->volumeId,namei_icreate(((void *)0), salvinfo->fileSysPath, isp->
volumeId, 0xffffffff, sp->inodeType, isp->RWvolumeId)
2429 INODESPECIAL, sp->inodeType, isp->RWvolumeId)namei_icreate(((void *)0), salvinfo->fileSysPath, isp->
volumeId, 0xffffffff, sp->inodeType, isp->RWvolumeId)
;
2430 if (!VALID_INO(*(sp->inode))((*(sp->inode)) != (Inode)-1 && (*(sp->inode)) !=
(Inode)0)
)
2431 Abort
2432 ("Unable to allocate inode (%s) for volume header (error = %d)\n",
2433 sp->description, errno(* __error()));
2434 }
2435 recreate = 1;
2436 }
2437
2438 IH_INIT(specH, salvinfo->fileSysDevice, isp->RWvolumeId, *(sp->inode))((specH) = ih_init((salvinfo->fileSysDevice), (isp->RWvolumeId
), (*(sp->inode))))
;
2439 fdP = IH_OPEN(specH)ih_open(specH);
2440 if (OKToZap && (fdP == NULL((void *)0)) && BadError(errno(* __error()))) {
2441 /* bail out early and destroy the volume */
2442 if (!Showmode)
2443 Log("Still can't open volume header inode (%s), destroying volume\n", sp->description);
2444 if (deleteMe)
2445 *deleteMe = 1;
2446 IH_RELEASE(specH)(ih_release(specH), (specH)=((void *)0), 0);
2447 return -1;
2448 }
2449 if (fdP == NULL((void *)0))
2450 Abort("Unable to open inode (%s) of volume header (error = %d)\n",
2451 sp->description, errno(* __error()));
2452
2453 if (!recreate
2454 && (FDH_PREAD(fdP, (char *)&header, sp->size, 0)pread((fdP)->fd_fd, (char *)&header, sp->size, 0) != sp->size
2455 || header.fileHeader.magic != sp->stamp.magic)) {
2456 if (check) {
2457 Log("Part of the header (%s) is corrupted\n", sp->description);
2458 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
2459 IH_RELEASE(specH)(ih_release(specH), (specH)=((void *)0), 0);
2460 return -1;
2461 }
2462 Log("Part of the header (%s) is corrupted; recreating\n",
2463 sp->description);
2464 recreate = 1;
2465 /* header can be garbage; make sure we don't read garbage data from
2466 * it below */
2467 memset(&header, 0, sizeof(header));
2468 }
2469 if (sp->inodeType == VI_VOLINFO1
2470 && header.volumeInfo.destroyMe == DESTROY_ME0xD3) {
2471 if (deleteMe)
2472 *deleteMe = 1;
2473 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
2474 IH_RELEASE(specH)(ih_release(specH), (specH)=((void *)0), 0);
2475 return -1;
2476 }
2477 if (recreate && !Testing) {
2478 if (check)
2479 Abort
2480 ("Internal error: recreating volume header (%s) in check mode\n",
2481 sp->description);
2482 nBytes = FDH_TRUNC(fdP, 0)ftruncate((fdP)->fd_fd, (off_t) (0));
2483 if (nBytes == -1)
2484 Abort("Unable to truncate volume header file (%s) (error = %d)\n",
2485 sp->description, errno(* __error()));
2486
2487 /* The following code should be moved into vutil.c */
2488 if (sp->inodeType == VI_VOLINFO1) {
2489 struct timeval tp;
2490 memset(&header.volumeInfo, 0, sizeof(header.volumeInfo));
2491 header.volumeInfo.stamp = sp->stamp;
2492 header.volumeInfo.id = isp->volumeId;
2493 header.volumeInfo.parentId = isp->RWvolumeId;
2494 sprintf(header.volumeInfo.name, "bogus.%u", isp->volumeId);
2495 Log("Warning: the name of volume %u is now \"bogus.%u\"\n",
2496 isp->volumeId, isp->volumeId);
2497 header.volumeInfo.inService = 0;
2498 header.volumeInfo.blessed = 0;
2499 /* The + 1000 is a hack in case there are any files out in venus caches */
2500 header.volumeInfo.uniquifier = (isp->maxUniquifier + 1) + 1000;
2501 header.volumeInfo.type = (isp->volumeId == isp->RWvolumeId ? readwriteVolume0 : readonlyVolume1); /* XXXX */
2502 header.volumeInfo.needsCallback = 0;
2503 gettimeofday(&tp, NULL((void *)0));
2504 header.volumeInfo.creationDate = tp.tv_sec;
2505 nBytes =
2506 FDH_PWRITE(fdP, (char *)&header.volumeInfo,pwrite((fdP)->fd_fd, (char *)&header.volumeInfo, sizeof
(header.volumeInfo), 0)
2507 sizeof(header.volumeInfo), 0)pwrite((fdP)->fd_fd, (char *)&header.volumeInfo, sizeof
(header.volumeInfo), 0)
;
2508 if (nBytes != sizeof(header.volumeInfo)) {
2509 if (nBytes < 0)
2510 Abort
2511 ("Unable to write volume header file (%s) (errno = %d)\n",
2512 sp->description, errno(* __error()));
2513 Abort("Unable to write entire volume header file (%s)\n",
2514 sp->description);
2515 }
2516 } else {
2517 nBytes = FDH_PWRITE(fdP, (char *)&sp->stamp, sizeof(sp->stamp), 0)pwrite((fdP)->fd_fd, (char *)&sp->stamp, sizeof(sp->
stamp), 0)
;
2518 if (nBytes != sizeof(sp->stamp)) {
2519 if (nBytes < 0)
2520 Abort
2521 ("Unable to write version stamp in volume header file (%s) (errno = %d)\n",
2522 sp->description, errno(* __error()));
2523 Abort
2524 ("Unable to write entire version stamp in volume header file (%s)\n",
2525 sp->description);
2526 }
2527 }
2528 }
2529 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
2530 IH_RELEASE(specH)(ih_release(specH), (specH)=((void *)0), 0);
2531 if (sp->inodeType == VI_VOLINFO1) {
2532 salvinfo->VolInfo = header.volumeInfo;
2533 if (check) {
2534 char update[25];
2535
2536 if (salvinfo->VolInfo.updateDate) {
2537 strcpy(update, TimeStamp(salvinfo->VolInfo.updateDate, 0));
2538 if (!Showmode)
2539 Log("%s (%u) %supdated %s\n", salvinfo->VolInfo.name,
2540 salvinfo->VolInfo.id,
2541 (Testing ? "it would have been " : ""), update);
2542 } else {
2543 strcpy(update, TimeStamp(salvinfo->VolInfo.creationDate, 0));
2544 if (!Showmode)
2545 Log("%s (%u) not updated (created %s)\n",
2546 salvinfo->VolInfo.name, salvinfo->VolInfo.id, update);
2547 }
2548
2549 }
2550 }
2551
2552 return 0;
2553}
2554
2555int
2556SalvageVnodes(struct SalvInfo *salvinfo,
2557 struct InodeSummary *rwIsp,
2558 struct InodeSummary *thisIsp,
2559 struct ViceInodeInfo *inodes, int check)
2560{
2561 int ilarge, ismall, ioffset, RW, nInodes;
2562 ioffset = rwIsp->index + rwIsp->nSpecialInodes; /* first inode */
2563 if (Showmode)
2564 return 0;
2565 RW = (rwIsp == thisIsp);
2566 nInodes = (rwIsp->nInodes - rwIsp->nSpecialInodes);
2567 ismall =
2568 SalvageIndex(salvinfo, thisIsp->volSummary->header.smallVnodeIndex, vSmall1, RW,
2569 &inodes[ioffset], nInodes, thisIsp->volSummary, check);
2570 if (check && ismall == -1)
2571 return -1;
2572 ilarge =
2573 SalvageIndex(salvinfo, thisIsp->volSummary->header.largeVnodeIndex, vLarge0, RW,
2574 &inodes[ioffset], nInodes, thisIsp->volSummary, check);
2575 return (ilarge == 0 && ismall == 0 ? 0 : -1);
2576}
2577
2578int
2579SalvageIndex(struct SalvInfo *salvinfo, Inode ino, VnodeClass class, int RW,
2580 struct ViceInodeInfo *ip, int nInodes,
2581 struct VolumeSummary *volSummary, int check)
2582{
2583 char buf[SIZEOF_LARGEDISKVNODE256];
2584 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
2585 int err = 0;
2586 StreamHandle_t *file;
2587 struct VnodeClassInfo *vcp;
2588 afs_sfsize_t size;
2589 afs_sfsize_t nVnodes;
2590 afs_fsize_t vnodeLength;
2591 int vnodeIndex;
2592 afs_ino_str_t stmp1, stmp2;
2593 IHandle_t *handle;
2594 FdHandle_t *fdP;
2595
2596 IH_INIT(handle, salvinfo->fileSysDevice, volSummary->header.parent, ino)((handle) = ih_init((salvinfo->fileSysDevice), (volSummary
->header.parent), (ino)))
;
2597 fdP = IH_OPEN(handle)ih_open(handle);
2598 osi_Assert(fdP != NULL)(void)((fdP != ((void *)0)) || (osi_AssertFailU("fdP != NULL"
, "./../vol/vol-salvage.c", 2598), 0))
;
2599 file = FDH_FDOPEN(fdP, "r+")stream_fdopen((fdP)->fd_fd);
2600 osi_Assert(file != NULL)(void)((file != ((void *)0)) || (osi_AssertFailU("file != NULL"
, "./../vol/vol-salvage.c", 2600), 0))
;
2601 vcp = &VnodeClassInfo[class];
2602 size = OS_SIZE(fdP->fd_fd)ih_size(fdP->fd_fd);
2603 osi_Assert(size != -1)(void)((size != -1) || (osi_AssertFailU("size != -1", "./../vol/vol-salvage.c"
, 2603), 0))
;
2604 nVnodes = (size / vcp->diskSize) - 1;
2605 if (nVnodes > 0) {
2606 osi_Assert((nVnodes + 1) * vcp->diskSize == size)(void)(((nVnodes + 1) * vcp->diskSize == size) || (osi_AssertFailU
("(nVnodes + 1) * vcp->diskSize == size", "./../vol/vol-salvage.c"
, 2606), 0))
;
2607 osi_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0)(void)((stream_aseek(file, vcp->diskSize) == 0) || (osi_AssertFailU
("STREAM_ASEEK(file, vcp->diskSize) == 0", "./../vol/vol-salvage.c"
, 2607), 0))
;
2608 } else {
2609 nVnodes = 0;
2610 }
2611 for (vnodeIndex = 0;
2612 nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file)stream_read(vnode, vcp->diskSize, 1, file) == 1;
2613 nVnodes--, vnodeIndex++) {
2614 if (vnode->type != vNull0) {
2615 int vnodeChanged = 0;
2616 int vnodeNumber = bitNumberToVnodeNumber(vnodeIndex, class)((VnodeId)(((vnodeIndex)<<1)+(class)+1));
2617 if (VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
== 0) {
2618 if (RW) {
2619 /* Log("### DEBUG ### Deleted Vnode with 0 inode (vnode %d)\n", vnodeNumber); */
2620 memset(vnode, 0, vcp->diskSize);
2621 vnodeChanged = 1;
2622 }
2623 } else {
2624 if (vcp->magic != vnode->vnodeMagic) {
2625 /* bad magic #, probably partially created vnode */
2626 if (check) {
2627 Log("Partially allocated vnode %d: bad magic (is %lx should be %lx)\n",
2628 vnodeNumber, afs_printable_uint32_lu(vnode->vnodeMagic),
2629 afs_printable_uint32_lu(vcp->magic));
2630 memset(vnode, 0, vcp->diskSize);
2631 err = -1;
2632 goto zooks;
2633 }
2634 Log("Partially allocated vnode %d deleted.\n",
2635 vnodeNumber);
2636 memset(vnode, 0, vcp->diskSize);
2637 vnodeChanged = 1;
2638 goto vnodeDone;
2639 }
2640 /* ****** Should do a bit more salvage here: e.g. make sure
2641 * vnode type matches what it should be given the index */
2642 while (nInodes && ip->u.vnode.vnodeNumber < vnodeNumber) {
2643/* if (vnodeIdToClass(ip->u.vnode.vnodeNumber) == class && RW) {
2644 * Log("Inode %d: says it belongs to non-existing vnode %d\n",
2645 * ip->inodeNumber, ip->u.vnode.vnodeNumber);
2646 * }
2647 */
2648 ip++;
2649 nInodes--;
2650 }
2651 if (!RW) {
2652 while (nInodes && ip->u.vnode.vnodeNumber == vnodeNumber) {
2653 /* The following doesn't work, because the version number
2654 * is not maintained correctly by the file server */
2655 /*if (vnode->uniquifier == ip->u.vnode.vnodeUniquifier &&
2656 * vnode->dataVersion == ip->u.vnode.inodeDataVersion)
2657 * break; */
2658 if (VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
== ip->inodeNumber)
2659 break;
2660 ip++;
2661 nInodes--;
2662 }
2663 } else {
2664 /* For RW volume, look for vnode with matching inode number;
2665 * if no such match, take the first determined by our sort
2666 * order */
2667 struct ViceInodeInfo *lip = ip;
2668 int lnInodes = nInodes;
2669 while (lnInodes
2670 && lip->u.vnode.vnodeNumber == vnodeNumber) {
2671 if (VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
== lip->inodeNumber) {
2672 ip = lip;
2673 nInodes = lnInodes;
2674 break;
2675 }
2676 lip++;
2677 lnInodes--;
2678 }
2679 }
2680 if (nInodes && ip->u.vnode.vnodeNumber == vnodeNumber) {
2681 /* "Matching" inode */
2682 if (RW) {
2683 Unique vu, iu;
2684 FileVersion vd, id;
2685 vu = vnode->uniquifier;
2686 iu = ip->u.vnode.vnodeUniquifier;
2687 vd = vnode->dataVersion;
2688 id = ip->u.vnode.inodeDataVersion;
2689 /*
2690 * Because of the possibility of the uniquifier overflows (> 4M)
2691 * we compare them modulo the low 22-bits; we shouldn't worry
2692 * about mismatching since they shouldn't to many old
2693 * uniquifiers of the same vnode...
2694 */
2695 if (IUnique(vu) != IUnique(iu)) {
2696 if (!Showmode) {
2697 Log("Vnode %u: vnode.unique, %u, does not match inode unique, %u; fixed, but status will be wrong\n", vnodeNumber, IUnique(vu), IUnique(iu));
2698 }
2699
2700 vnode->uniquifier = iu;
2701#ifdef AFS_3DISPARES
2702 vnode->dataVersion = (id >= vd ?
2703 /* 90% of 2.1M */
2704 ((id - vd) >
2705 1887437 ? vd : id) :
2706 /* 90% of 2.1M */
2707 ((vd - id) >
2708 1887437 ? id : vd));
2709#else
2710#if defined(AFS_SGI_EXMAG)
2711 vnode->dataVersion = (id >= vd ?
2712 /* 90% of 16M */
2713 ((id - vd) >
2714 15099494 ? vd : id) :
2715 /* 90% of 16M */
2716 ((vd - id) >
2717 15099494 ? id : vd));
2718#else
2719 vnode->dataVersion = (id > vd ? id : vd);
2720#endif /* AFS_SGI_EXMAG */
2721#endif /* AFS_3DISPARES */
2722 vnodeChanged = 1;
2723 } else {
2724 /* don't bother checking for vd > id any more, since
2725 * partial file transfers always result in this state,
2726 * and you can't do much else anyway (you've already
2727 * found the best data you can) */
2728#ifdef AFS_3DISPARES
2729 if (!vnodeIsDirectory(vnodeNumber)(((vnodeNumber-1)&((1<<1)-1)) == 0)
2730 && ((vd < id && (id - vd) < 1887437)
2731 || ((vd > id && (vd - id) > 1887437)))) {
2732#else
2733#if defined(AFS_SGI_EXMAG)
2734 if (!vnodeIsDirectory(vnodeNumber)(((vnodeNumber-1)&((1<<1)-1)) == 0)
2735 && ((vd < id && (id - vd) < 15099494)
2736 || ((vd > id && (vd - id) > 15099494)))) {
2737#else
2738 if (!vnodeIsDirectory(vnodeNumber)(((vnodeNumber-1)&((1<<1)-1)) == 0) && vd < id) {
2739#endif /* AFS_SGI_EXMAG */
2740#endif
2741 if (!Showmode)
2742 Log("Vnode %d: version < inode version; fixed (old status)\n", vnodeNumber);
2743 vnode->dataVersion = id;
2744 vnodeChanged = 1;
2745 }
2746 }
2747 }
2748 if (ip->inodeNumber != VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
) {
2749 if (check) {
2750 if (!Showmode) {
2751 Log("Vnode %d: inode number incorrect (is %s should be %s). FileSize=%llu\n", vnodeNumber, PrintInode(stmp1, VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
), PrintInode(stmp2, ip->inodeNumber), (afs_uintmax_t) ip->byteCount);
2752 }
2753 VNDISK_SET_INO(vnode, ip->inodeNumber)((vnode)->vn_ino_lo = (int)(ip->inodeNumber&0xffffffff
), ((vnode)->vn_ino_hi = (ip->inodeNumber) ? (int)(((ip
->inodeNumber)>>32)&0xffffffff) : 0))
;
2754 err = -1;
2755 goto zooks;
2756 }
2757 if (!Showmode) {
2758 Log("Vnode %d: inode number incorrect; changed from %s to %s. FileSize=%llu\n", vnodeNumber, PrintInode(stmp1, VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
), PrintInode(stmp2, ip->inodeNumber), (afs_uintmax_t) ip->byteCount);
2759 }
2760 VNDISK_SET_INO(vnode, ip->inodeNumber)((vnode)->vn_ino_lo = (int)(ip->inodeNumber&0xffffffff
), ((vnode)->vn_ino_hi = (ip->inodeNumber) ? (int)(((ip
->inodeNumber)>>32)&0xffffffff) : 0))
;
2761 vnodeChanged = 1;
2762 }
2763 VNDISK_GET_LEN(vnodeLength, vnode)(vnodeLength) = ((afs_int64)((vnode)->vn_length_hi) <<
32) | ((vnode)->length);
;
2764 if (ip->byteCount != vnodeLength) {
2765 if (check) {
2766 if (!Showmode)
2767 Log("Vnode %d: length incorrect; (is %llu should be %llu)\n", vnodeNumber, (afs_uintmax_t) vnodeLength, (afs_uintmax_t) ip->byteCount);
2768 err = -1;
2769 goto zooks;
2770 }
2771 if (!Showmode)
2772 Log("Vnode %d: length incorrect; changed from %llu to %llu\n", vnodeNumber, (afs_uintmax_t) vnodeLength, (afs_uintmax_t) ip->byteCount);
2773 VNDISK_SET_LEN(vnode, ip->byteCount)((vnode)->vn_length_hi) = ((afs_int64)ip->byteCount) >>
32; ((vnode)->length) = (ip->byteCount) & 0xFFFFFFFF
;
;
2774 vnodeChanged = 1;
2775 }
2776 if (!check)
2777 ip->linkCount--; /* Keep the inode around */
2778 ip++;
2779 nInodes--;
2780 } else { /* no matching inode */
2781 afs_ino_str_t stmp;
2782 if (VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
!= 0
2783 || vnode->type == vDirectory2) {
2784 /* No matching inode--get rid of the vnode */
2785 if (check) {
2786 if (VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
) {
2787 if (!Showmode) {
2788 Log("Vnode %d (unique %u): corresponding inode %s is missing\n", vnodeNumber, vnode->uniquifier, PrintInode(stmp, VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
));
2789 }
2790 } else {
2791 if (!Showmode)
2792 Log("Vnode %d (unique %u): bad directory vnode (no inode number listed)\n", vnodeNumber, vnode->uniquifier);
2793 }
2794 err = -1;
2795 goto zooks;
2796 }
2797 if (VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
) {
2798 if (!Showmode) {
2799 time_t serverModifyTime = vnode->serverModifyTime;
2800 Log("Vnode %d (unique %u): corresponding inode %s is missing; vnode deleted, vnode mod time=%s", vnodeNumber, vnode->uniquifier, PrintInode(stmp, VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
), ctime(&serverModifyTime));
2801 }
2802 } else {
2803 if (!Showmode) {
2804 time_t serverModifyTime = vnode->serverModifyTime;
2805 Log("Vnode %d (unique %u): bad directory vnode (no inode number listed); vnode deleted, vnode mod time=%s", vnodeNumber, vnode->uniquifier, ctime(&serverModifyTime));
2806 }
2807 }
2808 memset(vnode, 0, vcp->diskSize);
2809 vnodeChanged = 1;
2810 } else {
2811 /* Should not reach here becuase we checked for
2812 * (inodeNumber == 0) above. And where we zero the vnode,
2813 * we also goto vnodeDone.
2814 */
2815 }
2816 }
2817 while (nInodes && ip->u.vnode.vnodeNumber == vnodeNumber) {
2818 ip++;
2819 nInodes--;
2820 }
2821 } /* VNDISK_GET_INO(vnode) != 0 */
2822 vnodeDone:
2823 osi_Assert(!(vnodeChanged && check))(void)((!(vnodeChanged && check)) || (osi_AssertFailU
("!(vnodeChanged && check)", "./../vol/vol-salvage.c"
, 2823), 0))
;
2824 if (vnodeChanged && !Testing) {
2825 osi_Assert(IH_IWRITE(void)((namei_iwrite(handle, (((((vnodeNumber)-1)>>1)+1
)<<(vcp)->logSize), (char *)vnode, vcp->diskSize)
== vcp->diskSize) || (osi_AssertFailU("IH_IWRITE (handle, vnodeIndexOffset(vcp, vnodeNumber), (char *)vnode, vcp->diskSize) == vcp->diskSize"
, "./../vol/vol-salvage.c", 2828), 0))
2826 (handle, vnodeIndexOffset(vcp, vnodeNumber),(void)((namei_iwrite(handle, (((((vnodeNumber)-1)>>1)+1
)<<(vcp)->logSize), (char *)vnode, vcp->diskSize)
== vcp->diskSize) || (osi_AssertFailU("IH_IWRITE (handle, vnodeIndexOffset(vcp, vnodeNumber), (char *)vnode, vcp->diskSize) == vcp->diskSize"
, "./../vol/vol-salvage.c", 2828), 0))
2827 (char *)vnode, vcp->diskSize)(void)((namei_iwrite(handle, (((((vnodeNumber)-1)>>1)+1
)<<(vcp)->logSize), (char *)vnode, vcp->diskSize)
== vcp->diskSize) || (osi_AssertFailU("IH_IWRITE (handle, vnodeIndexOffset(vcp, vnodeNumber), (char *)vnode, vcp->diskSize) == vcp->diskSize"
, "./../vol/vol-salvage.c", 2828), 0))
2828 == vcp->diskSize)(void)((namei_iwrite(handle, (((((vnodeNumber)-1)>>1)+1
)<<(vcp)->logSize), (char *)vnode, vcp->diskSize)
== vcp->diskSize) || (osi_AssertFailU("IH_IWRITE (handle, vnodeIndexOffset(vcp, vnodeNumber), (char *)vnode, vcp->diskSize) == vcp->diskSize"
, "./../vol/vol-salvage.c", 2828), 0))
;
2829 salvinfo->VolumeChanged = 1; /* For break call back */
2830 }
2831 }
2832 }
2833 zooks:
2834 STREAM_CLOSE(file)stream_close(file, 0);
2835 FDH_CLOSE(fdP)(fd_close(fdP), (fdP)=((void *)0), 0);
2836 IH_RELEASE(handle)(ih_release(handle), (handle)=((void *)0), 0);
2837 return err;
2838}
2839
2840struct VnodeEssence *
2841CheckVnodeNumber(struct SalvInfo *salvinfo, VnodeId vnodeNumber)
2842{
2843 VnodeClass class;
2844 struct VnodeInfo *vip;
2845 int offset;
2846
2847 class = vnodeIdToClass(vnodeNumber)((vnodeNumber-1)&((1<<1)-1));
2848 vip = &salvinfo->vnodeInfo[class];
2849 offset = vnodeIdToBitNumber(vnodeNumber)(((vnodeNumber)-1)>>1);
2850 return (offset >= vip->nVnodes ? NULL((void *)0) : &vip->vnodes[offset]);
2851}
2852
2853void
2854CopyOnWrite(struct SalvInfo *salvinfo, struct DirSummary *dir)
2855{
2856 /* Copy the directory unconditionally if we are going to change it:
2857 * not just if was cloned.
2858 */
2859 struct VnodeDiskObject vnode;
2860 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge0];
2861 Inode oldinode, newinode;
2862 afs_sfsize_t code;
2863
2864 if (dir->copied || Testing)
2865 return;
2866 DFlush(); /* Well justified paranoia... */
2867
2868 code =
2869 IH_IREAD(salvinfo->vnodeInfo[vLarge].handle,namei_iread(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
2870 vnodeIndexOffset(vcp, dir->vnodeNumber), (char *)&vnode,namei_iread(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
2871 sizeof(vnode))namei_iread(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
;
2872 osi_Assert(code == sizeof(vnode))(void)((code == sizeof(vnode)) || (osi_AssertFailU("code == sizeof(vnode)"
, "./../vol/vol-salvage.c", 2872), 0))
;
2873 oldinode = VNDISK_GET_INO(&vnode)((Inode)((&vnode)->vn_ino_lo | ((&vnode)->vn_ino_hi
? (((Inode)(&vnode)->vn_ino_hi)<<32) : 0)))
;
2874 /* Increment the version number by a whole lot to avoid problems with
2875 * clients that were promised new version numbers--but the file server
2876 * crashed before the versions were written to disk.
2877 */
2878 newinode =
2879 IH_CREATE(dir->ds_linkH, salvinfo->fileSysDevice, salvinfo->fileSysPath, 0, dir->rwVid,namei_icreate(dir->ds_linkH, salvinfo->fileSysPath, dir
->rwVid, dir->vnodeNumber, vnode.uniquifier, vnode.dataVersion
+= 200)
2880 dir->vnodeNumber, vnode.uniquifier, vnode.dataVersion +=namei_icreate(dir->ds_linkH, salvinfo->fileSysPath, dir
->rwVid, dir->vnodeNumber, vnode.uniquifier, vnode.dataVersion
+= 200)
2881 200)namei_icreate(dir->ds_linkH, salvinfo->fileSysPath, dir
->rwVid, dir->vnodeNumber, vnode.uniquifier, vnode.dataVersion
+= 200)
;
2882 osi_Assert(VALID_INO(newinode))(void)((((newinode) != (Inode)-1 && (newinode) != (Inode
)0)) || (osi_AssertFailU("VALID_INO(newinode)", "./../vol/vol-salvage.c"
, 2882), 0))
;
2883 osi_Assert(CopyInode(salvinfo->fileSysDevice, oldinode, newinode, dir->rwVid) == 0)(void)((CopyInode(salvinfo->fileSysDevice, oldinode, newinode
, dir->rwVid) == 0) || (osi_AssertFailU("CopyInode(salvinfo->fileSysDevice, oldinode, newinode, dir->rwVid) == 0"
, "./../vol/vol-salvage.c", 2883), 0))
;
2884 vnode.cloned = 0;
2885 VNDISK_SET_INO(&vnode, newinode)((&vnode)->vn_ino_lo = (int)(newinode&0xffffffff),
((&vnode)->vn_ino_hi = (newinode) ? (int)(((newinode)
>>32)&0xffffffff) : 0))
;
2886 code =
2887 IH_IWRITE(salvinfo->vnodeInfo[vLarge].handle,namei_iwrite(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
2888 vnodeIndexOffset(vcp, dir->vnodeNumber), (char *)&vnode,namei_iwrite(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
2889 sizeof(vnode))namei_iwrite(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
;
2890 osi_Assert(code == sizeof(vnode))(void)((code == sizeof(vnode)) || (osi_AssertFailU("code == sizeof(vnode)"
, "./../vol/vol-salvage.c", 2890), 0))
;
2891
2892 SetSalvageDirHandle(&dir->dirHandle, dir->dirHandle.dirh_handle->ih_vid,
2893 salvinfo->fileSysDevice, newinode,
2894 &salvinfo->VolumeChanged);
2895 /* Don't delete the original inode right away, because the directory is
2896 * still being scanned.
2897 */
2898 dir->copied = 1;
2899}
2900
2901/*
2902 * This function should either successfully create a new dir, or give up
2903 * and leave things the way they were. In particular, if it fails to write
2904 * the new dir properly, it should return w/o changing the reference to the
2905 * old dir.
2906 */
2907void
2908CopyAndSalvage(struct SalvInfo *salvinfo, struct DirSummary *dir)
2909{
2910 struct VnodeDiskObject vnode;
2911 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge0];
2912 Inode oldinode, newinode;
2913 DirHandle newdir;
2914 FdHandle_t *fdP;
2915 afs_int32 code;
2916 afs_sfsize_t lcode;
2917 afs_int32 parentUnique = 1;
2918 struct VnodeEssence *vnodeEssence;
2919 afs_fsize_t length;
2920
2921 if (Testing)
2922 return;
2923 Log("Salvaging directory %u...\n", dir->vnodeNumber);
2924 lcode =
2925 IH_IREAD(salvinfo->vnodeInfo[vLarge].handle,namei_iread(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
2926 vnodeIndexOffset(vcp, dir->vnodeNumber), (char *)&vnode,namei_iread(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
2927 sizeof(vnode))namei_iread(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
;
2928 osi_Assert(lcode == sizeof(vnode))(void)((lcode == sizeof(vnode)) || (osi_AssertFailU("lcode == sizeof(vnode)"
, "./../vol/vol-salvage.c", 2928), 0))
;
2929 oldinode = VNDISK_GET_INO(&vnode)((Inode)((&vnode)->vn_ino_lo | ((&vnode)->vn_ino_hi
? (((Inode)(&vnode)->vn_ino_hi)<<32) : 0)))
;
2930 /* Increment the version number by a whole lot to avoid problems with
2931 * clients that were promised new version numbers--but the file server
2932 * crashed before the versions were written to disk.
2933 */
2934 newinode =
2935 IH_CREATE(dir->ds_linkH, salvinfo->fileSysDevice, salvinfo->fileSysPath, 0, dir->rwVid,namei_icreate(dir->ds_linkH, salvinfo->fileSysPath, dir
->rwVid, dir->vnodeNumber, vnode.uniquifier, vnode.dataVersion
+= 200)
2936 dir->vnodeNumber, vnode.uniquifier, vnode.dataVersion +=namei_icreate(dir->ds_linkH, salvinfo->fileSysPath, dir
->rwVid, dir->vnodeNumber, vnode.uniquifier, vnode.dataVersion
+= 200)
2937 200)namei_icreate(dir->ds_linkH, salvinfo->fileSysPath, dir
->rwVid, dir->vnodeNumber, vnode.uniquifier, vnode.dataVersion
+= 200)
;
2938 osi_Assert(VALID_INO(newinode))(void)((((newinode) != (Inode)-1 && (newinode) != (Inode
)0)) || (osi_AssertFailU("VALID_INO(newinode)", "./../vol/vol-salvage.c"
, 2938), 0))
;
2939 SetSalvageDirHandle(&newdir, dir->rwVid, salvinfo->fileSysDevice, newinode,
2940 &salvinfo->VolumeChanged);
2941
2942 /* Assign . and .. vnode numbers from dir and vnode.parent.
2943 * The uniquifier for . is in the vnode.
2944 * The uniquifier for .. might be set to a bogus value of 1 and
2945 * the salvager will later clean it up.
2946 */
2947 if (vnode.parent && (vnodeEssence = CheckVnodeNumber(salvinfo, vnode.parent))) {
2948 parentUnique = (vnodeEssence->unique ? vnodeEssence->unique : 1);
2949 }
2950 code =
2951 DirSalvage(&dir->dirHandle, &newdir, dir->vnodeNumber,
2952 vnode.uniquifier,
2953 (vnode.parent ? vnode.parent : dir->vnodeNumber),
2954 parentUnique);
2955 if (code == 0)
2956 code = DFlush();
2957 if (code) {
2958 /* didn't really build the new directory properly, let's just give up. */
2959 code = IH_DEC(dir->ds_linkH, newinode, dir->rwVid)namei_dec(dir->ds_linkH, newinode, dir->rwVid);
2960 Log("Directory salvage returned code %d, continuing.\n", code);
2961 if (code) {
2962 Log("also failed to decrement link count on new inode");
2963 }
2964 osi_Assert(1 == 2)(void)((1 == 2) || (osi_AssertFailU("1 == 2", "./../vol/vol-salvage.c"
, 2964), 0))
;
2965 }
2966 Log("Checking the results of the directory salvage...\n");
2967 if (!DirOK(&newdir)) {
2968 Log("Directory salvage failed!!!; restoring old version of the directory.\n");
2969 code = IH_DEC(dir->ds_linkH, newinode, dir->rwVid)namei_dec(dir->ds_linkH, newinode, dir->rwVid);
2970 osi_Assert(code == 0)(void)((code == 0) || (osi_AssertFailU("code == 0", "./../vol/vol-salvage.c"
, 2970), 0))
;
2971 osi_Assert(1 == 2)(void)((1 == 2) || (osi_AssertFailU("1 == 2", "./../vol/vol-salvage.c"
, 2971), 0))
;
2972 }
2973 vnode.cloned = 0;
2974 VNDISK_SET_INO(&vnode, newinode)((&vnode)->vn_ino_lo = (int)(newinode&0xffffffff),
((&vnode)->vn_ino_hi = (newinode) ? (int)(((newinode)
>>32)&0xffffffff) : 0))
;
2975 length = afs_dir_Length(&newdir);
2976 VNDISK_SET_LEN(&vnode, length)((&vnode)->vn_length_hi) = ((afs_int64)length) >>
32; ((&vnode)->length) = (length) & 0xFFFFFFFF;
;
2977 lcode =
2978 IH_IWRITE(salvinfo->vnodeInfo[vLarge].handle,namei_iwrite(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
2979 vnodeIndexOffset(vcp, dir->vnodeNumber), (char *)&vnode,namei_iwrite(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
2980 sizeof(vnode))namei_iwrite(salvinfo->vnodeInfo[0].handle, (((((dir->vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
;
2981 osi_Assert(lcode == sizeof(vnode))(void)((lcode == sizeof(vnode)) || (osi_AssertFailU("lcode == sizeof(vnode)"
, "./../vol/vol-salvage.c", 2981), 0))
;
2982#if 0
2983#ifdef AFS_NT40_ENV
2984 nt_sync(salvinfo->fileSysDevice);
2985#else
2986 sync(); /* this is slow, but hopefully rarely called. We don't have
2987 * an open FD on the file itself to fsync.
2988 */
2989#endif
2990#else
2991 salvinfo->vnodeInfo[vLarge0].handle->ih_synced = 1;
2992#endif
2993 /* make sure old directory file is really closed */
2994 fdP = IH_OPEN(dir->dirHandle.dirh_handle)ih_open(dir->dirHandle.dirh_handle);
2995 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
2996
2997 code = IH_DEC(dir->ds_linkH, oldinode, dir->rwVid)namei_dec(dir->ds_linkH, oldinode, dir->rwVid);
2998 osi_Assert(code == 0)(void)((code == 0) || (osi_AssertFailU("code == 0", "./../vol/vol-salvage.c"
, 2998), 0))
;
2999 dir->dirHandle = newdir;
3000}
3001
3002/**
3003 * arguments for JudgeEntry.
3004 */
3005struct judgeEntry_params {
3006 struct DirSummary *dir; /**< directory we're examining entries in */
3007 struct SalvInfo *salvinfo; /**< SalvInfo for the current salvage job */
3008};
3009
3010int
3011JudgeEntry(void *arock, char *name, afs_int32 vnodeNumber,
3012 afs_int32 unique)
3013{
3014 struct judgeEntry_params *params = arock;
3015 struct DirSummary *dir = params->dir;
3016 struct SalvInfo *salvinfo = params->salvinfo;
3017 struct VnodeEssence *vnodeEssence;
3018 afs_int32 dirOrphaned, todelete;
3019
3020 dirOrphaned = IsVnodeOrphaned(salvinfo, dir->vnodeNumber);
3021
3022 vnodeEssence = CheckVnodeNumber(salvinfo, vnodeNumber);
3023 if (vnodeEssence == NULL((void *)0)) {
3024 if (!Showmode) {
3025 Log("dir vnode %u: invalid entry deleted: %s" OS_DIRSEP"/" "%s (vnode %u, unique %u)\n", dir->vnodeNumber, dir->name ? dir->name : "??", name, vnodeNumber, unique);
3026 }
3027 if (!Testing) {
3028 CopyOnWrite(salvinfo, dir);
3029 osi_Assert(afs_dir_Delete(&dir->dirHandle, name) == 0)(void)((afs_dir_Delete(&dir->dirHandle, name) == 0) ||
(osi_AssertFailU("afs_dir_Delete(&dir->dirHandle, name) == 0"
, "./../vol/vol-salvage.c", 3029), 0))
;
3030 }
3031 return 0;
3032 }
3033#ifdef AFS_AIX_ENV
3034#ifndef AFS_NAMEI_ENV1
3035 /* On AIX machines, don't allow entries to point to inode 0. That is a special
3036 * mount inode for the partition. If this inode were deleted, it would crash
3037 * the machine.
3038 */
3039 if (vnodeEssence->InodeNumber == 0) {
3040 Log("dir vnode %d: invalid entry: %s" OS_DIRSEP"/" "%s has no inode (vnode %d, unique %d)%s\n", dir->vnodeNumber, (dir->name ? dir->name : "??"), name, vnodeNumber, unique, (Testing ? "-- would have deleted" : " -- deleted"));
3041 if (!Testing) {
3042 CopyOnWrite(salvinfo, dir);
3043 osi_Assert(Delete(&dir->dirHandle, name) == 0)(void)((Delete(&dir->dirHandle, name) == 0) || (osi_AssertFailU
("Delete(&dir->dirHandle, name) == 0", "./../vol/vol-salvage.c"
, 3043), 0))
;
3044 }
3045 return 0;
3046 }
3047#endif
3048#endif
3049
3050 if (!(vnodeNumber & 1) && !Showmode
3051 && !(vnodeEssence->count || vnodeEssence->unique
3052 || vnodeEssence->modeBits)) {
3053 Log("dir vnode %u: invalid entry: %s" OS_DIRSEP"/" "%s (vnode %u, unique %u)%s\n",
3054 dir->vnodeNumber, (dir->name ? dir->name : "??"), name,
3055 vnodeNumber, unique,
3056 ((!unique) ? (Testing ? "-- would have deleted" : " -- deleted") :
3057 ""));
3058 if (!unique) {
3059 if (!Testing) {
3060 CopyOnWrite(salvinfo, dir);
3061 osi_Assert(afs_dir_Delete(&dir->dirHandle, name) == 0)(void)((afs_dir_Delete(&dir->dirHandle, name) == 0) ||
(osi_AssertFailU("afs_dir_Delete(&dir->dirHandle, name) == 0"
, "./../vol/vol-salvage.c", 3061), 0))
;
3062 }
3063 return 0;
3064 }
3065 }
3066
3067 /* Check if the Uniquifiers match. If not, change the directory entry
3068 * so its unique matches the vnode unique. Delete if the unique is zero
3069 * or if the directory is orphaned.
3070 */
3071 if (!vnodeEssence->unique || (vnodeEssence->unique) != unique) {
3072 if (!vnodeEssence->unique
3073 && ((strcmp(name, "..") == 0) || (strcmp(name, ".") == 0))) {
3074 /* This is an orphaned directory. Don't delete the . or ..
3075 * entry. Otherwise, it will get created in the next
3076 * salvage and deleted again here. So Just skip it.
3077 */
3078 return 0;
3079 }
3080
3081 todelete = ((!vnodeEssence->unique || dirOrphaned) ? 1 : 0);
3082
3083 if (!Showmode) {
3084 Log("dir vnode %u: %s" OS_DIRSEP"/" "%s (vnode %u): unique changed from %u to %u %s\n", dir->vnodeNumber, (dir->name ? dir->name : "??"), name, vnodeNumber, unique, vnodeEssence->unique, (!todelete ? "" : (Testing ? "-- would have deleted" : "-- deleted")));
3085 }
3086 if (!Testing) {
3087 AFSFid fid;
3088 fid.Vnode = vnodeNumber;
3089 fid.Unique = vnodeEssence->unique;
3090 CopyOnWrite(salvinfo, dir);
3091 osi_Assert(afs_dir_Delete(&dir->dirHandle, name) == 0)(void)((afs_dir_Delete(&dir->dirHandle, name) == 0) ||
(osi_AssertFailU("afs_dir_Delete(&dir->dirHandle, name) == 0"
, "./../vol/vol-salvage.c", 3091), 0))
;
3092 if (!todelete)
3093 osi_Assert(afs_dir_Create(&dir->dirHandle, name, &fid) == 0)(void)((afs_dir_Create(&dir->dirHandle, name, &fid
) == 0) || (osi_AssertFailU("afs_dir_Create(&dir->dirHandle, name, &fid) == 0"
, "./../vol/vol-salvage.c", 3093), 0))
;
3094 }
3095 if (todelete)
3096 return 0; /* no need to continue */
3097 }
3098
3099 if (strcmp(name, ".") == 0) {
3100 if (dir->vnodeNumber != vnodeNumber || (dir->unique != unique)) {
3101 AFSFid fid;
3102 if (!Showmode)
3103 Log("directory vnode %u.%u: bad '.' entry (was %u.%u); fixed\n", dir->vnodeNumber, dir->unique, vnodeNumber, unique);
3104 if (!Testing) {
3105 CopyOnWrite(salvinfo, dir);
3106 osi_Assert(afs_dir_Delete(&dir->dirHandle, ".") == 0)(void)((afs_dir_Delete(&dir->dirHandle, ".") == 0) || (
osi_AssertFailU("afs_dir_Delete(&dir->dirHandle, \".\") == 0"
, "./../vol/vol-salvage.c", 3106), 0))
;
3107 fid.Vnode = dir->vnodeNumber;
3108 fid.Unique = dir->unique;
3109 osi_Assert(afs_dir_Create(&dir->dirHandle, ".", &fid) == 0)(void)((afs_dir_Create(&dir->dirHandle, ".", &fid)
== 0) || (osi_AssertFailU("afs_dir_Create(&dir->dirHandle, \".\", &fid) == 0"
, "./../vol/vol-salvage.c", 3109), 0))
;
3110 }
3111
3112 vnodeNumber = fid.Vnode; /* Get the new Essence */
3113 unique = fid.Unique;
3114 vnodeEssence = CheckVnodeNumber(salvinfo, vnodeNumber);
3115 }
3116 dir->haveDot = 1;
3117 } else if (strcmp(name, "..") == 0) {
3118 AFSFid pa;
3119 if (dir->parent) {
3120 struct VnodeEssence *dotdot;
3121 pa.Vnode = dir->parent;
3122 dotdot = CheckVnodeNumber(salvinfo, pa.Vnode);
3123 osi_Assert(dotdot != NULL)(void)((dotdot != ((void *)0)) || (osi_AssertFailU("dotdot != NULL"
, "./../vol/vol-salvage.c", 3123), 0))
; /* XXX Should not be assert */
3124 pa.Unique = dotdot->unique;
3125 } else {
3126 pa.Vnode = dir->vnodeNumber;
3127 pa.Unique = dir->unique;
3128 }
3129 if ((pa.Vnode != vnodeNumber) || (pa.Unique != unique)) {
3130 if (!Showmode)
3131 Log("directory vnode %u.%u: bad '..' entry (was %u.%u); fixed\n", dir->vnodeNumber, dir->unique, vnodeNumber, unique);
3132 if (!Testing) {
3133 CopyOnWrite(salvinfo, dir);
3134 osi_Assert(afs_dir_Delete(&dir->dirHandle, "..") == 0)(void)((afs_dir_Delete(&dir->dirHandle, "..") == 0) ||
(osi_AssertFailU("afs_dir_Delete(&dir->dirHandle, \"..\") == 0"
, "./../vol/vol-salvage.c", 3134), 0))
;
3135 osi_Assert(afs_dir_Create(&dir->dirHandle, "..", &pa) == 0)(void)((afs_dir_Create(&dir->dirHandle, "..", &pa)
== 0) || (osi_AssertFailU("afs_dir_Create(&dir->dirHandle, \"..\", &pa) == 0"
, "./../vol/vol-salvage.c", 3135), 0))
;
3136 }
3137
3138 vnodeNumber = pa.Vnode; /* Get the new Essence */
3139 unique = pa.Unique;
3140 vnodeEssence = CheckVnodeNumber(salvinfo, vnodeNumber);
3141 }
3142 dir->haveDotDot = 1;
3143 } else if (strncmp(name, ".__afs", 6) == 0) {
3144 if (!Showmode) {
3145 Log("dir vnode %u: special old unlink-while-referenced file %s %s deleted (vnode %u)\n", dir->vnodeNumber, name, (Testing ? "would have been" : "is"), vnodeNumber);
3146 }
3147 if (!Testing) {
3148 CopyOnWrite(salvinfo, dir);
3149 osi_Assert(afs_dir_Delete(&dir->dirHandle, name) == 0)(void)((afs_dir_Delete(&dir->dirHandle, name) == 0) ||
(osi_AssertFailU("afs_dir_Delete(&dir->dirHandle, name) == 0"
, "./../vol/vol-salvage.c", 3149), 0))
;
3150 }
3151 vnodeEssence->claimed = 0; /* Not claimed: Orphaned */
3152 vnodeEssence->todelete = 1; /* Will later delete vnode and decr inode */
3153 return 0;
3154 } else {
3155 if (ShowSuid && (vnodeEssence->modeBits & 06000))
3156 Log("FOUND suid/sgid file: %s" OS_DIRSEP"/" "%s (%u.%u %05o) author %u (vnode %u dir %u)\n", dir->name ? dir->name : "??", name, vnodeEssence->owner, vnodeEssence->group, vnodeEssence->modeBits, vnodeEssence->author, vnodeNumber, dir->vnodeNumber);
3157 if (/* ShowMounts && */ (vnodeEssence->type == vSymlink3)
3158 && !(vnodeEssence->modeBits & 0111)) {
3159 afs_sfsize_t nBytes;
3160 afs_sfsize_t size;
3161 char buf[1025];
3162 IHandle_t *ihP;
3163 FdHandle_t *fdP;
3164
3165 IH_INIT(ihP, salvinfo->fileSysDevice, dir->dirHandle.dirh_handle->ih_vid,((ihP) = ih_init((salvinfo->fileSysDevice), (dir->dirHandle
.dirh_handle->ih_vid), (vnodeEssence->InodeNumber)))
3166 vnodeEssence->InodeNumber)((ihP) = ih_init((salvinfo->fileSysDevice), (dir->dirHandle
.dirh_handle->ih_vid), (vnodeEssence->InodeNumber)))
;
3167 fdP = IH_OPEN(ihP)ih_open(ihP);
3168 if (fdP == NULL((void *)0)) {
3169 Log("ERROR %s could not open mount point vnode %u\n", dir->vname, vnodeNumber);
3170 IH_RELEASE(ihP)(ih_release(ihP), (ihP)=((void *)0), 0);
3171 return 0;
3172 }
3173 size = FDH_SIZE(fdP)ih_size((fdP)->fd_fd);
3174 if (size < 0) {
3175 Log("ERROR %s mount point has invalid size %d, vnode %u\n", dir->vname, (int)size, vnodeNumber);
3176 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
3177 IH_RELEASE(ihP)(ih_release(ihP), (ihP)=((void *)0), 0);
3178 return 0;
3179 }
3180
3181 if (size > 1024)
3182 size = 1024;
3183 nBytes = FDH_PREAD(fdP, buf, size, 0)pread((fdP)->fd_fd, buf, size, 0);
3184 if (nBytes == size) {
3185 buf[size] = '\0';
3186 if ( (*buf != '#' && *buf != '%') || buf[strlen(buf)-1] != '.' ) {
3187 Log("Volume %u (%s) mount point %s" OS_DIRSEP"/" "%s to '%s' invalid, %s to symbolic link\n",
3188 dir->dirHandle.dirh_handle->ih_vid, dir->vname, dir->name ? dir->name : "??", name, buf,
3189 Testing ? "would convert" : "converted");
3190 vnodeEssence->modeBits |= 0111;
3191 vnodeEssence->changed = 1;
3192 } else if (ShowMounts) Log("In volume %u (%s) found mountpoint %s" OS_DIRSEP"/" "%s to '%s'\n",
3193 dir->dirHandle.dirh_handle->ih_vid, dir->vname,
3194 dir->name ? dir->name : "??", name, buf);
3195 } else {
3196 Log("Volume %s cound not read mount point vnode %u size %d code %d\n",
3197 dir->vname, vnodeNumber, (int)size, (int)nBytes);
3198 }
3199 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
3200 IH_RELEASE(ihP)(ih_release(ihP), (ihP)=((void *)0), 0);
3201 }
3202 if (ShowRootFiles && vnodeEssence->owner == 0 && vnodeNumber != 1)
3203 Log("FOUND root file: %s" OS_DIRSEP"/" "%s (%u.%u %05o) author %u (vnode %u dir %u)\n", dir->name ? dir->name : "??", name, vnodeEssence->owner, vnodeEssence->group, vnodeEssence->modeBits, vnodeEssence->author, vnodeNumber, dir->vnodeNumber);
3204 if (vnodeIdToClass(vnodeNumber)((vnodeNumber-1)&((1<<1)-1)) == vLarge0
3205 && vnodeEssence->name == NULL((void *)0)) {
3206 char *n;
3207 if ((n = (char *)malloc(strlen(name) + 1)))
3208 strcpy(n, name);
3209 vnodeEssence->name = n;
3210 }
3211
3212 /* The directory entry points to the vnode. Check to see if the
3213 * vnode points back to the directory. If not, then let the
3214 * directory claim it (else it might end up orphaned). Vnodes
3215 * already claimed by another directory are deleted from this
3216 * directory: hardlinks to the same vnode are not allowed
3217 * from different directories.
3218 */
3219 if (vnodeEssence->parent != dir->vnodeNumber) {
3220 if (!vnodeEssence->claimed && !dirOrphaned && vnodeNumber != 1) {
3221 /* Vnode does not point back to this directory.
3222 * Orphaned dirs cannot claim a file (it may belong to
3223 * another non-orphaned dir).
3224 */
3225 if (!Showmode) {
3226 Log("dir vnode %u: %s" OS_DIRSEP"/" "%s (vnode %u, unique %u) -- parent vnode %schanged from %u to %u\n", dir->vnodeNumber, (dir->name ? dir->name : "??"), name, vnodeNumber, unique, (Testing ? "would have been " : ""), vnodeEssence->parent, dir->vnodeNumber);
3227 }
3228 vnodeEssence->parent = dir->vnodeNumber;
3229 vnodeEssence->changed = 1;
3230 } else {
3231 /* Vnode was claimed by another directory */
3232 if (!Showmode) {
3233 if (dirOrphaned) {
3234 Log("dir vnode %u: %s" OS_DIRSEP"/" "%s parent vnode is %u (vnode %u, unique %u) -- %sdeleted\n", dir->vnodeNumber, (dir->name ? dir->name : "??"), name, vnodeEssence->parent, vnodeNumber, unique, (Testing ? "would have been " : ""));
3235 } else if (vnodeNumber == 1) {
3236 Log("dir vnode %d: %s" OS_DIRSEP"/" "%s is invalid (vnode %d, unique %d) -- %sdeleted\n", dir->vnodeNumber, (dir->name ? dir->name : "??"), name, vnodeNumber, unique, (Testing ? "would have been " : ""));
3237 } else {
3238 Log("dir vnode %u: %s" OS_DIRSEP"/" "%s already claimed by directory vnode %u (vnode %u, unique %u) -- %sdeleted\n", dir->vnodeNumber, (dir->name ? dir->name : "??"), name, vnodeEssence->parent, vnodeNumber, unique, (Testing ? "would have been " : ""));
3239 }
3240 }
3241 if (!Testing) {
3242 CopyOnWrite(salvinfo, dir);
3243 osi_Assert(afs_dir_Delete(&dir->dirHandle, name) == 0)(void)((afs_dir_Delete(&dir->dirHandle, name) == 0) ||
(osi_AssertFailU("afs_dir_Delete(&dir->dirHandle, name) == 0"
, "./../vol/vol-salvage.c", 3243), 0))
;
3244 }
3245 return 0;
3246 }
3247 }
3248 /* This directory claims the vnode */
3249 vnodeEssence->claimed = 1;
3250 }
3251 vnodeEssence->count--;
3252 return 0;
3253}
3254
3255void
3256DistilVnodeEssence(struct SalvInfo *salvinfo, VolumeId rwVId,
3257 VnodeClass class, Inode ino, Unique * maxu)
3258{
3259 struct VnodeInfo *vip = &salvinfo->vnodeInfo[class];
3260 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
3261 char buf[SIZEOF_LARGEDISKVNODE256];
3262 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
3263 afs_sfsize_t size;
3264 StreamHandle_t *file;
3265 int vnodeIndex;
3266 int nVnodes;
3267 FdHandle_t *fdP;
3268
3269 IH_INIT(vip->handle, salvinfo->fileSysDevice, rwVId, ino)((vip->handle) = ih_init((salvinfo->fileSysDevice), (rwVId
), (ino)))
;
3270 fdP = IH_OPEN(vip->handle)ih_open(vip->handle);
3271 osi_Assert(fdP != NULL)(void)((fdP != ((void *)0)) || (osi_AssertFailU("fdP != NULL"
, "./../vol/vol-salvage.c", 3271), 0))
;
3272 file = FDH_FDOPEN(fdP, "r+")stream_fdopen((fdP)->fd_fd);
3273 osi_Assert(file != NULL)(void)((file != ((void *)0)) || (osi_AssertFailU("file != NULL"
, "./../vol/vol-salvage.c", 3273), 0))
;
3274 size = OS_SIZE(fdP->fd_fd)ih_size(fdP->fd_fd);
3275 osi_Assert(size != -1)(void)((size != -1) || (osi_AssertFailU("size != -1", "./../vol/vol-salvage.c"
, 3275), 0))
;
3276 vip->nVnodes = (size / vcp->diskSize) - 1;
3277 if (vip->nVnodes > 0) {
3278 osi_Assert((vip->nVnodes + 1) * vcp->diskSize == size)(void)(((vip->nVnodes + 1) * vcp->diskSize == size) || (
osi_AssertFailU("(vip->nVnodes + 1) * vcp->diskSize == size"
, "./../vol/vol-salvage.c", 3278), 0))
;
3279 osi_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0)(void)((stream_aseek(file, vcp->diskSize) == 0) || (osi_AssertFailU
("STREAM_ASEEK(file, vcp->diskSize) == 0", "./../vol/vol-salvage.c"
, 3279), 0))
;
3280 osi_Assert((vip->vnodes = (struct VnodeEssence *)(void)(((vip->vnodes = (struct VnodeEssence *) calloc(vip->
nVnodes, sizeof(struct VnodeEssence))) != ((void *)0)) || (osi_AssertFailU
("(vip->vnodes = (struct VnodeEssence *) calloc(vip->nVnodes, sizeof(struct VnodeEssence))) != NULL"
, "./../vol/vol-salvage.c", 3281), 0))
3281 calloc(vip->nVnodes, sizeof(struct VnodeEssence))) != NULL)(void)(((vip->vnodes = (struct VnodeEssence *) calloc(vip->
nVnodes, sizeof(struct VnodeEssence))) != ((void *)0)) || (osi_AssertFailU
("(vip->vnodes = (struct VnodeEssence *) calloc(vip->nVnodes, sizeof(struct VnodeEssence))) != NULL"
, "./../vol/vol-salvage.c", 3281), 0))
;
3282 if (class == vLarge0) {
3283 osi_Assert((vip->inodes = (Inode *)(void)(((vip->inodes = (Inode *) calloc(vip->nVnodes, sizeof
(Inode))) != ((void *)0)) || (osi_AssertFailU("(vip->inodes = (Inode *) calloc(vip->nVnodes, sizeof(Inode))) != NULL"
, "./../vol/vol-salvage.c", 3284), 0))
3284 calloc(vip->nVnodes, sizeof(Inode))) != NULL)(void)(((vip->inodes = (Inode *) calloc(vip->nVnodes, sizeof
(Inode))) != ((void *)0)) || (osi_AssertFailU("(vip->inodes = (Inode *) calloc(vip->nVnodes, sizeof(Inode))) != NULL"
, "./../vol/vol-salvage.c", 3284), 0))
;
3285 } else {
3286 vip->inodes = NULL((void *)0);
3287 }
3288 } else {
3289 vip->nVnodes = 0;
3290 vip->vnodes = NULL((void *)0);
3291 vip->inodes = NULL((void *)0);
3292 }
3293 vip->volumeBlockCount = vip->nAllocatedVnodes = 0;
3294 for (vnodeIndex = 0, nVnodes = vip->nVnodes;
3295 nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file)stream_read(vnode, vcp->diskSize, 1, file) == 1;
3296 nVnodes--, vnodeIndex++) {
3297 if (vnode->type != vNull0) {
3298 struct VnodeEssence *vep = &vip->vnodes[vnodeIndex];
3299 afs_fsize_t vnodeLength;
3300 vip->nAllocatedVnodes++;
3301 vep->count = vnode->linkCount;
3302 VNDISK_GET_LEN(vnodeLength, vnode)(vnodeLength) = ((afs_int64)((vnode)->vn_length_hi) <<
32) | ((vnode)->length);
;
3303 vep->blockCount = nBlocks(vnodeLength)((afs_sfsize_t)((vnodeLength) == 0? 1: (((afs_sfsize_t)(vnodeLength
))+1023)/1024))
;
3304 vip->volumeBlockCount += vep->blockCount;
3305 vep->parent = vnode->parent;
3306 vep->unique = vnode->uniquifier;
3307 if (*maxu < vnode->uniquifier)
3308 *maxu = vnode->uniquifier;
3309 vep->modeBits = vnode->modeBits;
3310 vep->InodeNumber = VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
;
3311 vep->type = vnode->type;
3312 vep->author = vnode->author;
3313 vep->owner = vnode->owner;
3314 vep->group = vnode->group;
3315 if (vnode->type == vDirectory2) {
3316 if (class != vLarge0) {
3317 VnodeId vnodeNumber = bitNumberToVnodeNumber(vnodeIndex, class)((VnodeId)(((vnodeIndex)<<1)+(class)+1));
3318 vip->nAllocatedVnodes--;
3319 memset(vnode, 0, sizeof(vnode));
3320 IH_IWRITE(salvinfo->vnodeInfo[vSmall].handle,namei_iwrite(salvinfo->vnodeInfo[1].handle, (((((vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
3321 vnodeIndexOffset(vcp, vnodeNumber),namei_iwrite(salvinfo->vnodeInfo[1].handle, (((((vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
3322 (char *)&vnode, sizeof(vnode))namei_iwrite(salvinfo->vnodeInfo[1].handle, (((((vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
;
3323 salvinfo->VolumeChanged = 1;
3324 } else
3325 vip->inodes[vnodeIndex] = VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
;
3326 }
3327 }
3328 }
3329 STREAM_CLOSE(file)stream_close(file, 0);
3330 FDH_CLOSE(fdP)(fd_close(fdP), (fdP)=((void *)0), 0);
3331}
3332
3333static char *
3334GetDirName(struct SalvInfo *salvinfo, VnodeId vnode, struct VnodeEssence *vp,
3335 char *path)
3336{
3337 struct VnodeEssence *parentvp;
3338
3339 if (vnode == 1) {
3340 strcpy(path, ".");
3341 return path;
3342 }
3343 if (vp->parent && vp->name && (parentvp = CheckVnodeNumber(salvinfo, vp->parent))
3344 && GetDirName(salvinfo, vp->parent, parentvp, path)) {
3345 strcat(path, OS_DIRSEP"/");
3346 strcat(path, vp->name);
3347 return path;
3348 }
3349 return 0;
3350}
3351
3352/* To determine if a vnode is orhpaned or not, the vnode and all its parent
3353 * vnodes must be "claimed". The vep->claimed flag is set in JudgeEntry().
3354 */
3355static int
3356IsVnodeOrphaned(struct SalvInfo *salvinfo, VnodeId vnode)
3357{
3358 struct VnodeEssence *vep;
3359
3360 if (vnode == 0)
3361 return (1); /* Vnode zero does not exist */
3362 if (vnode == 1)
3363 return (0); /* The root dir vnode is always claimed */
3364 vep = CheckVnodeNumber(salvinfo, vnode); /* Get the vnode essence */
3365 if (!vep || !vep->claimed)
3366 return (1); /* Vnode is not claimed - it is orphaned */
3367
3368 return (IsVnodeOrphaned(salvinfo, vep->parent));
3369}
3370
3371void
3372SalvageDir(struct SalvInfo *salvinfo, char *name, VolumeId rwVid,
3373 struct VnodeInfo *dirVnodeInfo, IHandle_t * alinkH, int i,
3374 struct DirSummary *rootdir, int *rootdirfound)
3375{
3376 static struct DirSummary dir;
3377 static struct DirHandle dirHandle;
3378 struct VnodeEssence *parent;
3379 static char path[MAXPATHLEN1024];
3380 int dirok, code;
3381
3382 if (dirVnodeInfo->vnodes[i].salvaged)
3383 return; /* already salvaged */
3384
3385 dir.rwVid = rwVid;
3386 dirVnodeInfo->vnodes[i].salvaged = 1;
3387
3388 if (dirVnodeInfo->inodes[i] == 0)
3389 return; /* Not allocated to a directory */
3390
3391 if (bitNumberToVnodeNumber(i, vLarge)((VnodeId)(((i)<<1)+(0)+1)) == 1) {
3392 if (dirVnodeInfo->vnodes[i].parent) {
3393 Log("Bad parent, vnode 1; %s...\n",
3394 (Testing ? "skipping" : "salvaging"));
3395 dirVnodeInfo->vnodes[i].parent = 0;
3396 dirVnodeInfo->vnodes[i].changed = 1;
3397 }
3398 } else {
3399 parent = CheckVnodeNumber(salvinfo, dirVnodeInfo->vnodes[i].parent);
3400 if (parent && parent->salvaged == 0)
3401 SalvageDir(salvinfo, name, rwVid, dirVnodeInfo, alinkH,
3402 vnodeIdToBitNumber(dirVnodeInfo->vnodes[i].parent)(((dirVnodeInfo->vnodes[i].parent)-1)>>1),
3403 rootdir, rootdirfound);
3404 }
3405
3406 dir.vnodeNumber = bitNumberToVnodeNumber(i, vLarge)((VnodeId)(((i)<<1)+(0)+1));
3407 dir.unique = dirVnodeInfo->vnodes[i].unique;
3408 dir.copied = 0;
3409 dir.vname = name;
3410 dir.parent = dirVnodeInfo->vnodes[i].parent;
3411 dir.haveDot = dir.haveDotDot = 0;
3412 dir.ds_linkH = alinkH;
3413 SetSalvageDirHandle(&dir.dirHandle, dir.rwVid, salvinfo->fileSysDevice,
3414 dirVnodeInfo->inodes[i], &salvinfo->VolumeChanged);
3415
3416 dirok = ((RebuildDirs && !Testing) ? 0 : DirOK(&dir.dirHandle));
3417 if (!dirok) {
3418 if (!RebuildDirs) {
3419 Log("Directory bad, vnode %u; %s...\n", dir.vnodeNumber,
3420 (Testing ? "skipping" : "salvaging"));
3421 }
3422 if (!Testing) {
3423 CopyAndSalvage(salvinfo, &dir);
3424 dirok = 1;
3425 dirVnodeInfo->inodes[i] = dir.dirHandle.dirh_inode;
3426 }
3427 }
3428 dirHandle = dir.dirHandle;
3429
3430 dir.name =
3431 GetDirName(salvinfo, bitNumberToVnodeNumber(i, vLarge)((VnodeId)(((i)<<1)+(0)+1)),
3432 &dirVnodeInfo->vnodes[i], path);
3433
3434 if (dirok) {
3435 /* If enumeration failed for random reasons, we will probably delete
3436 * too much stuff, so we guard against this instead.
3437 */
3438 struct judgeEntry_params judge_params;
3439 judge_params.salvinfo = salvinfo;
3440 judge_params.dir = &dir;
3441
3442 osi_Assert(afs_dir_EnumerateDir(&dirHandle, JudgeEntry,(void)((afs_dir_EnumerateDir(&dirHandle, JudgeEntry, &
judge_params) == 0) || (osi_AssertFailU("afs_dir_EnumerateDir(&dirHandle, JudgeEntry, &judge_params) == 0"
, "./../vol/vol-salvage.c", 3443), 0))
3443 &judge_params) == 0)(void)((afs_dir_EnumerateDir(&dirHandle, JudgeEntry, &
judge_params) == 0) || (osi_AssertFailU("afs_dir_EnumerateDir(&dirHandle, JudgeEntry, &judge_params) == 0"
, "./../vol/vol-salvage.c", 3443), 0))
;
3444 }
3445
3446 /* Delete the old directory if it was copied in order to salvage.
3447 * CopyOnWrite has written the new inode # to the disk, but we still
3448 * have the old one in our local structure here. Thus, we idec the
3449 * local dude.
3450 */
3451 DFlush();
3452 if (dir.copied && !Testing) {
3453 code = IH_DEC(dir.ds_linkH, dirHandle.dirh_handle->ih_ino, rwVid)namei_dec(dir.ds_linkH, dirHandle.dirh_handle->ih_ino, rwVid
)
;
3454 osi_Assert(code == 0)(void)((code == 0) || (osi_AssertFailU("code == 0", "./../vol/vol-salvage.c"
, 3454), 0))
;
3455 dirVnodeInfo->inodes[i] = dir.dirHandle.dirh_inode;
3456 }
3457
3458 /* Remember rootdir DirSummary _after_ it has been judged */
3459 if (dir.vnodeNumber == 1 && dir.unique == 1) {
3460 memcpy(rootdir, &dir, sizeof(struct DirSummary));
3461 *rootdirfound = 1;
3462 }
3463
3464 return;
3465}
3466
3467/**
3468 * Get a new FID that can be used to create a new file.
3469 *
3470 * @param[in] volHeader vol header for the volume
3471 * @param[in] class what type of vnode we'll be creating (vLarge or vSmall)
3472 * @param[out] afid the FID that we can use (only Vnode and Unique are set)
3473 * @param[inout] maxunique max uniquifier for all vnodes in the volume;
3474 * updated to the new max unique if we create a new
3475 * vnode
3476 */
3477static void
3478GetNewFID(struct SalvInfo *salvinfo, VolumeDiskData *volHeader,
3479 VnodeClass class, AFSFid *afid, Unique *maxunique)
3480{
3481 int i;
3482 for (i = 0; i < salvinfo->vnodeInfo[class].nVnodes; i++) {
3483 if (salvinfo->vnodeInfo[class].vnodes[i].type == vNull0) {
3484 break;
3485 }
3486 }
3487 if (i == salvinfo->vnodeInfo[class].nVnodes) {
3488 /* no free vnodes; make a new one */
3489 salvinfo->vnodeInfo[class].nVnodes++;
3490 salvinfo->vnodeInfo[class].vnodes =
3491 realloc(salvinfo->vnodeInfo[class].vnodes,
3492 sizeof(struct VnodeEssence) * (i+1));
3493
3494 salvinfo->vnodeInfo[class].vnodes[i].type = vNull0;
3495 }
3496
3497 afid->Vnode = bitNumberToVnodeNumber(i, class)((VnodeId)(((i)<<1)+(class)+1));
3498
3499 if (volHeader->uniquifier < (*maxunique + 1)) {
3500 /* header uniq is bad; it will get bumped by 2000 later */
3501 afid->Unique = *maxunique + 1 + 2000;
3502 (*maxunique)++;
3503 } else {
3504 /* header uniq seems okay; just use that */
3505 afid->Unique = *maxunique = volHeader->uniquifier++;
3506 }
3507}
3508
3509/**
3510 * Create a vnode for a README file explaining not to use a recreated-root vol.
3511 *
3512 * @param[in] volHeader vol header for the volume
3513 * @param[in] alinkH ihandle for i/o for the volume
3514 * @param[in] vid volume id
3515 * @param[inout] maxunique max uniquifier for all vnodes in the volume;
3516 * updated to the new max unique if we create a new
3517 * vnode
3518 * @param[out] afid FID for the new readme vnode
3519 * @param[out] ainode the inode for the new readme file
3520 *
3521 * @return operation status
3522 * @retval 0 success
3523 * @retval -1 error
3524 */
3525static int
3526CreateReadme(struct SalvInfo *salvinfo, VolumeDiskData *volHeader,
3527 IHandle_t *alinkH, VolumeId vid, Unique *maxunique, AFSFid *afid,
3528 Inode *ainode)
3529{
3530 Inode readmeinode;
3531 struct VnodeDiskObject *rvnode = NULL((void *)0);
3532 afs_sfsize_t bytes;
3533 IHandle_t *readmeH = NULL((void *)0);
3534 struct VnodeEssence *vep;
3535 afs_fsize_t length;
3536 time_t now = time(NULL((void *)0));
3537
3538 /* Try to make the note brief, but informative. Only administrators should
3539 * be able to read this file at first, so we can hopefully assume they
3540 * know what AFS is, what a volume is, etc. */
3541 char readme[] =
3542"This volume has been salvaged, but has lost its original root directory.\n"
3543"The root directory that exists now has been recreated from orphan files\n"
3544"from the rest of the volume. This recreated root directory may interfere\n"
3545"with old cached data on clients, and there is no way the salvager can\n"
3546"reasonably prevent that. So, it is recommended that you do not continue to\n"
3547"use this volume, but only copy the salvaged data to a new volume.\n"
3548"Continuing to use this volume as it exists now may cause some clients to\n"
3549"behave oddly when accessing this volume.\n"
3550"\n\t -- Your friendly neighborhood OpenAFS salvager\n";
3551 /* ^ the person reading this probably just lost some data, so they could
3552 * use some cheering up. */
3553
3554 /* -1 for the trailing NUL */
3555 length = sizeof(readme) - 1;
3556
3557 GetNewFID(salvinfo, volHeader, vSmall1, afid, maxunique);
3558
3559 vep = &salvinfo->vnodeInfo[vSmall1].vnodes[vnodeIdToBitNumber(afid->Vnode)(((afid->Vnode)-1)>>1)];
3560
3561 /* create the inode and write the contents */
3562 readmeinode = IH_CREATE(alinkH, salvinfo->fileSysDevice,namei_icreate(alinkH, salvinfo->fileSysPath, vid, afid->
Vnode, afid->Unique, 1)
3563 salvinfo->fileSysPath, 0, vid,namei_icreate(alinkH, salvinfo->fileSysPath, vid, afid->
Vnode, afid->Unique, 1)
3564 afid->Vnode, afid->Unique, 1)namei_icreate(alinkH, salvinfo->fileSysPath, vid, afid->
Vnode, afid->Unique, 1)
;
3565 if (!VALID_INO(readmeinode)((readmeinode) != (Inode)-1 && (readmeinode) != (Inode
)0)
) {
3566 Log("CreateReadme: readme IH_CREATE failed\n");
3567 goto error;
3568 }
3569
3570 IH_INIT(readmeH, salvinfo->fileSysDevice, vid, readmeinode)((readmeH) = ih_init((salvinfo->fileSysDevice), (vid), (readmeinode
)))
;
3571 bytes = IH_IWRITE(readmeH, 0, readme, length)namei_iwrite(readmeH, 0, readme, length);
3572 IH_RELEASE(readmeH)(ih_release(readmeH), (readmeH)=((void *)0), 0);
3573
3574 if (bytes != length) {
3575 Log("CreateReadme: IWRITE failed (%d/%d)\n", (int)bytes,
3576 (int)sizeof(readme));
3577 goto error;
3578 }
3579
3580 /* create the vnode and write it out */
3581 rvnode = calloc(1, SIZEOF_SMALLDISKVNODE64);
3582 if (!rvnode) {
3583 Log("CreateRootDir: error alloc'ing memory\n");
3584 goto error;
3585 }
3586
3587 rvnode->type = vFile1;
3588 rvnode->cloned = 0;
3589 rvnode->modeBits = 0777;
3590 rvnode->linkCount = 1;
3591 VNDISK_SET_LEN(rvnode, length)((rvnode)->vn_length_hi) = ((afs_int64)length) >> 32
; ((rvnode)->length) = (length) & 0xFFFFFFFF;
;
3592 rvnode->uniquifier = afid->Unique;
3593 rvnode->dataVersion = 1;
3594 VNDISK_SET_INO(rvnode, readmeinode)((rvnode)->vn_ino_lo = (int)(readmeinode&0xffffffff), (
(rvnode)->vn_ino_hi = (readmeinode) ? (int)(((readmeinode)
>>32)&0xffffffff) : 0))
;
3595 rvnode->unixModifyTime = rvnode->serverModifyTime = now;
3596 rvnode->author = 0;
3597 rvnode->owner = 0;
3598 rvnode->parent = 1;
3599 rvnode->group = 0;
3600 rvnode->vnodeMagic = VnodeClassInfo[vSmall1].magic;
3601
3602 bytes = IH_IWRITE(salvinfo->vnodeInfo[vSmall].handle,namei_iwrite(salvinfo->vnodeInfo[1].handle, (((((afid->
Vnode)-1)>>1)+1)<<(&VnodeClassInfo[1])->logSize
), (char*)rvnode, 64)
3603 vnodeIndexOffset(&VnodeClassInfo[vSmall], afid->Vnode),namei_iwrite(salvinfo->vnodeInfo[1].handle, (((((afid->
Vnode)-1)>>1)+1)<<(&VnodeClassInfo[1])->logSize
), (char*)rvnode, 64)
3604 (char*)rvnode, SIZEOF_SMALLDISKVNODE)namei_iwrite(salvinfo->vnodeInfo[1].handle, (((((afid->
Vnode)-1)>>1)+1)<<(&VnodeClassInfo[1])->logSize
), (char*)rvnode, 64)
;
3605
3606 if (bytes != SIZEOF_SMALLDISKVNODE64) {
3607 Log("CreateReadme: IH_IWRITE failed (%d/%d)\n", (int)bytes,
3608 (int)SIZEOF_SMALLDISKVNODE64);
3609 goto error;
3610 }
3611
3612 /* update VnodeEssence for new readme vnode */
3613 salvinfo->vnodeInfo[vSmall1].nAllocatedVnodes++;
3614 vep->count = 0;
3615 vep->blockCount = nBlocks(length)((afs_sfsize_t)((length) == 0? 1: (((afs_sfsize_t)(length))+1023
)/1024))
;
3616 salvinfo->vnodeInfo[vSmall1].volumeBlockCount += vep->blockCount;
3617 vep->parent = rvnode->parent;
3618 vep->unique = rvnode->uniquifier;
3619 vep->modeBits = rvnode->modeBits;
3620 vep->InodeNumber = VNDISK_GET_INO(rvnode)((Inode)((rvnode)->vn_ino_lo | ((rvnode)->vn_ino_hi ? (
((Inode)(rvnode)->vn_ino_hi)<<32) : 0)))
;
3621 vep->type = rvnode->type;
3622 vep->author = rvnode->author;
3623 vep->owner = rvnode->owner;
3624 vep->group = rvnode->group;
3625
3626 free(rvnode);
3627 rvnode = NULL((void *)0);
3628
3629 vep->claimed = 1;
3630 vep->changed = 0;
3631 vep->salvaged = 1;
3632 vep->todelete = 0;
3633
3634 *ainode = readmeinode;
3635
3636 return 0;
3637
3638 error:
3639 if (IH_DEC(alinkH, readmeinode, vid)namei_dec(alinkH, readmeinode, vid)) {
3640 Log("CreateReadme (recovery): IH_DEC failed\n");
3641 }
3642
3643 if (rvnode) {
3644 free(rvnode);
3645 rvnode = NULL((void *)0);
3646 }
3647
3648 return -1;
3649}
3650
3651/**
3652 * create a root dir for a volume that lacks one.
3653 *
3654 * @param[in] volHeader vol header for the volume
3655 * @param[in] alinkH ihandle for disk access for this volume group
3656 * @param[in] vid volume id we're dealing with
3657 * @param[out] rootdir populated with info about the new root dir
3658 * @param[inout] maxunique max uniquifier for all vnodes in the volume;
3659 * updated to the new max unique if we create a new
3660 * vnode
3661 *
3662 * @return operation status
3663 * @retval 0 success
3664 * @retval -1 error
3665 */
3666static int
3667CreateRootDir(struct SalvInfo *salvinfo, VolumeDiskData *volHeader,
3668 IHandle_t *alinkH, VolumeId vid, struct DirSummary *rootdir,
3669 Unique *maxunique)
3670{
3671 FileVersion dv;
3672 int decroot = 0, decreadme = 0;
3673 AFSFid did, readmeid;
3674 afs_fsize_t length;
3675 Inode rootinode;
3676 struct VnodeDiskObject *rootvnode = NULL((void *)0);
3677 struct acl_accessList *ACL;
3678 Inode *ip;
3679 afs_sfsize_t bytes;
3680 struct VnodeEssence *vep;
3681 Inode readmeinode;
3682 time_t now = time(NULL((void *)0));
3683
3684 if (!salvinfo->vnodeInfo[vLarge0].vnodes && !salvinfo->vnodeInfo[vSmall1].vnodes) {
3685 Log("Not creating new root dir; volume appears to lack any vnodes\n");
3686 goto error;
3687 }
3688
3689 if (!salvinfo->vnodeInfo[vLarge0].vnodes) {
3690 /* We don't have any large vnodes in the volume; allocate room
3691 * for one so we can recreate the root dir */
3692 salvinfo->vnodeInfo[vLarge0].nVnodes = 1;
3693 salvinfo->vnodeInfo[vLarge0].vnodes = calloc(1, sizeof(struct VnodeEssence));
3694 salvinfo->vnodeInfo[vLarge0].inodes = calloc(1, sizeof(Inode));
3695
3696 osi_Assert(salvinfo->vnodeInfo[vLarge].vnodes)(void)((salvinfo->vnodeInfo[0].vnodes) || (osi_AssertFailU
("salvinfo->vnodeInfo[vLarge].vnodes", "./../vol/vol-salvage.c"
, 3696), 0))
;
3697 osi_Assert(salvinfo->vnodeInfo[vLarge].inodes)(void)((salvinfo->vnodeInfo[0].inodes) || (osi_AssertFailU
("salvinfo->vnodeInfo[vLarge].inodes", "./../vol/vol-salvage.c"
, 3697), 0))
;
3698 }
3699
3700 vep = &salvinfo->vnodeInfo[vLarge0].vnodes[vnodeIdToBitNumber(1)(((1)-1)>>1)];
3701 ip = &salvinfo->vnodeInfo[vLarge0].inodes[vnodeIdToBitNumber(1)(((1)-1)>>1)];
3702 if (vep->type != vNull0) {
3703 Log("Not creating new root dir; existing vnode 1 is non-null\n");
3704 goto error;
3705 }
3706
3707 if (CreateReadme(salvinfo, volHeader, alinkH, vid, maxunique, &readmeid,
3708 &readmeinode) != 0) {
3709 goto error;
3710 }
3711 decreadme = 1;
3712
3713 /* set the DV to a very high number, so it is unlikely that we collide
3714 * with a cached DV */
3715 dv = 1 << 30;
3716
3717 rootinode = IH_CREATE(alinkH, salvinfo->fileSysDevice, salvinfo->fileSysPath,namei_icreate(alinkH, salvinfo->fileSysPath, vid, 1, 1, dv
)
3718 0, vid, 1, 1, dv)namei_icreate(alinkH, salvinfo->fileSysPath, vid, 1, 1, dv
)
;
3719 if (!VALID_INO(rootinode)((rootinode) != (Inode)-1 && (rootinode) != (Inode)0)) {
3720 Log("CreateRootDir: IH_CREATE failed\n");
3721 goto error;
3722 }
3723 decroot = 1;
3724
3725 SetSalvageDirHandle(&rootdir->dirHandle, vid, salvinfo->fileSysDevice,
3726 rootinode, &salvinfo->VolumeChanged);
3727 did.Volume = vid;
3728 did.Vnode = 1;
3729 did.Unique = 1;
3730 if (afs_dir_MakeDir(&rootdir->dirHandle, (afs_int32*)&did, (afs_int32*)&did)) {
3731 Log("CreateRootDir: MakeDir failed\n");
3732 goto error;
3733 }
3734 if (afs_dir_Create(&rootdir->dirHandle, "README.ROOTDIR", &readmeid)) {
3735 Log("CreateRootDir: Create failed\n");
3736 goto error;
3737 }
3738 DFlush();
3739 length = afs_dir_Length(&rootdir->dirHandle);
3740 DZap(&rootdir->dirHandle);
3741
3742 /* create the new root dir vnode */
3743 rootvnode = calloc(1, SIZEOF_LARGEDISKVNODE256);
3744 if (!rootvnode) {
3745 Log("CreateRootDir: malloc failed\n");
3746 goto error;
3747 }
3748
3749 /* only give 'rl' permissions to 'system:administrators'. We do this to
3750 * try to catch the attention of an administrator, that they should not
3751 * be writing to this directory or continue to use it. */
3752 ACL = VVnodeDiskACL(rootvnode)((AL_AccessList *) (((byte *)(rootvnode))+64));
3753 ACL->size = sizeof(struct acl_accessList);
3754 ACL->version = ACL_ACLVERSION1;
3755 ACL->total = 1;
3756 ACL->positive = 1;
3757 ACL->negative = 0;
3758 ACL->entries[0].id = -204; /* system:administrators */
3759 ACL->entries[0].rights = PRSFS_READ1 | PRSFS_LOOKUP8;
3760
3761 rootvnode->type = vDirectory2;
3762 rootvnode->cloned = 0;
3763 rootvnode->modeBits = 0777;
3764 rootvnode->linkCount = 2;
3765 VNDISK_SET_LEN(rootvnode, length)((rootvnode)->vn_length_hi) = ((afs_int64)length) >>
32; ((rootvnode)->length) = (length) & 0xFFFFFFFF;
;
3766 rootvnode->uniquifier = 1;
3767 rootvnode->dataVersion = dv;
3768 VNDISK_SET_INO(rootvnode, rootinode)((rootvnode)->vn_ino_lo = (int)(rootinode&0xffffffff),
((rootvnode)->vn_ino_hi = (rootinode) ? (int)(((rootinode
)>>32)&0xffffffff) : 0))
;
3769 rootvnode->unixModifyTime = rootvnode->serverModifyTime = now;
3770 rootvnode->author = 0;
3771 rootvnode->owner = 0;
3772 rootvnode->parent = 0;
3773 rootvnode->group = 0;
3774 rootvnode->vnodeMagic = VnodeClassInfo[vLarge0].magic;
3775
3776 /* write it out to disk */
3777 bytes = IH_IWRITE(salvinfo->vnodeInfo[vLarge].handle,namei_iwrite(salvinfo->vnodeInfo[0].handle, (((((1)-1)>>
1)+1)<<(&VnodeClassInfo[0])->logSize), (char*)rootvnode
, 256)
3778 vnodeIndexOffset(&VnodeClassInfo[vLarge], 1),namei_iwrite(salvinfo->vnodeInfo[0].handle, (((((1)-1)>>
1)+1)<<(&VnodeClassInfo[0])->logSize), (char*)rootvnode
, 256)
3779 (char*)rootvnode, SIZEOF_LARGEDISKVNODE)namei_iwrite(salvinfo->vnodeInfo[0].handle, (((((1)-1)>>
1)+1)<<(&VnodeClassInfo[0])->logSize), (char*)rootvnode
, 256)
;
3780
3781 if (bytes != SIZEOF_LARGEDISKVNODE256) {
3782 /* just cast to int and don't worry about printing real 64-bit ints;
3783 * a large disk vnode isn't anywhere near the 32-bit limit */
3784 Log("CreateRootDir: IH_IWRITE failed (%d/%d)\n", (int)bytes,
3785 (int)SIZEOF_LARGEDISKVNODE256);
3786 goto error;
3787 }
3788
3789 /* update VnodeEssence for the new root vnode */
3790 salvinfo->vnodeInfo[vLarge0].nAllocatedVnodes++;
3791 vep->count = 0;
3792 vep->blockCount = nBlocks(length)((afs_sfsize_t)((length) == 0? 1: (((afs_sfsize_t)(length))+1023
)/1024))
;
3793 salvinfo->vnodeInfo[vLarge0].volumeBlockCount += vep->blockCount;
3794 vep->parent = rootvnode->parent;
3795 vep->unique = rootvnode->uniquifier;
3796 vep->modeBits = rootvnode->modeBits;
3797 vep->InodeNumber = VNDISK_GET_INO(rootvnode)((Inode)((rootvnode)->vn_ino_lo | ((rootvnode)->vn_ino_hi
? (((Inode)(rootvnode)->vn_ino_hi)<<32) : 0)))
;
3798 vep->type = rootvnode->type;
3799 vep->author = rootvnode->author;
3800 vep->owner = rootvnode->owner;
3801 vep->group = rootvnode->group;
3802
3803 free(rootvnode);
3804 rootvnode = NULL((void *)0);
3805
3806 vep->claimed = 0;
3807 vep->changed = 0;
3808 vep->salvaged = 1;
3809 vep->todelete = 0;
3810
3811 /* update DirSummary for the new root vnode */
3812 rootdir->vnodeNumber = 1;
3813 rootdir->unique = 1;
3814 rootdir->haveDot = 1;
3815 rootdir->haveDotDot = 1;
3816 rootdir->rwVid = vid;
3817 rootdir->copied = 0;
3818 rootdir->parent = 0;
3819 rootdir->name = strdup(".");
3820 rootdir->vname = volHeader->name;
3821 rootdir->ds_linkH = alinkH;
3822
3823 *ip = rootinode;
3824
3825 return 0;
3826
3827 error:
3828 if (decroot && IH_DEC(alinkH, rootinode, vid)namei_dec(alinkH, rootinode, vid)) {
3829 Log("CreateRootDir (recovery): IH_DEC (root) failed\n");
3830 }
3831 if (decreadme && IH_DEC(alinkH, readmeinode, vid)namei_dec(alinkH, readmeinode, vid)) {
3832 Log("CreateRootDir (recovery): IH_DEC (readme) failed\n");
3833 }
3834 if (rootvnode) {
3835 free(rootvnode);
3836 rootvnode = NULL((void *)0);
3837 }
3838 return -1;
3839}
3840
3841/**
3842 * salvage a volume group.
3843 *
3844 * @param[in] salvinfo information for the curent salvage job
3845 * @param[in] rwIsp inode summary for rw volume
3846 * @param[in] alinkH link table inode handle
3847 *
3848 * @return operation status
3849 * @retval 0 success
3850 */
3851int
3852SalvageVolume(struct SalvInfo *salvinfo, struct InodeSummary *rwIsp, IHandle_t * alinkH)
3853{
3854 /* This routine, for now, will only be called for read-write volumes */
3855 int i, j, code;
3856 int BlocksInVolume = 0, FilesInVolume = 0;
3857 VnodeClass class;
3858 struct DirSummary rootdir, oldrootdir;
3859 struct VnodeInfo *dirVnodeInfo;
3860 struct VnodeDiskObject vnode;
3861 VolumeDiskData volHeader;
3862 VolumeId vid;
3863 int orphaned, rootdirfound = 0;
3864 Unique maxunique = 0; /* the maxUniquifier from the vnodes */
3865 afs_int32 ofiles = 0, oblocks = 0; /* Number of orphaned files/blocks */
3866 struct VnodeEssence *vep;
3867 afs_int32 v, pv;
3868 IHandle_t *h;
3869 afs_sfsize_t nBytes;
3870 AFSFid pa;
3871 VnodeId LFVnode, ThisVnode;
3872 Unique LFUnique, ThisUnique;
3873 char npath[128];
3874 int newrootdir = 0;
3875
3876 vid = rwIsp->volSummary->header.id;
3877 IH_INIT(h, salvinfo->fileSysDevice, vid, rwIsp->volSummary->header.volumeInfo)((h) = ih_init((salvinfo->fileSysDevice), (vid), (rwIsp->
volSummary->header.volumeInfo)))
;
3878 nBytes = IH_IREAD(h, 0, (char *)&volHeader, sizeof(volHeader))namei_iread(h, 0, (char *)&volHeader, sizeof(volHeader));
3879 osi_Assert(nBytes == sizeof(volHeader))(void)((nBytes == sizeof(volHeader)) || (osi_AssertFailU("nBytes == sizeof(volHeader)"
, "./../vol/vol-salvage.c", 3879), 0))
;
3880 osi_Assert(volHeader.stamp.magic == VOLUMEINFOMAGIC)(void)((volHeader.stamp.magic == ((bit32)0x78a1b2c5)) || (osi_AssertFailU
("volHeader.stamp.magic == VOLUMEINFOMAGIC", "./../vol/vol-salvage.c"
, 3880), 0))
;
3881 osi_Assert(volHeader.destroyMe != DESTROY_ME)(void)((volHeader.destroyMe != 0xD3) || (osi_AssertFailU("volHeader.destroyMe != DESTROY_ME"
, "./../vol/vol-salvage.c", 3881), 0))
;
3882 /* (should not have gotten this far with DESTROY_ME flag still set!) */
3883
3884 DistilVnodeEssence(salvinfo, vid, vLarge0,
3885 rwIsp->volSummary->header.largeVnodeIndex, &maxunique);
3886 DistilVnodeEssence(salvinfo, vid, vSmall1,
3887 rwIsp->volSummary->header.smallVnodeIndex, &maxunique);
3888
3889 dirVnodeInfo = &salvinfo->vnodeInfo[vLarge0];
3890 for (i = 0; i < dirVnodeInfo->nVnodes; i++) {
3891 SalvageDir(salvinfo, volHeader.name, vid, dirVnodeInfo, alinkH, i,
3892 &rootdir, &rootdirfound);
3893 }
3894#ifdef AFS_NT40_ENV
3895 nt_sync(salvinfo->fileSysDevice);
3896#else
3897 sync(); /* This used to be done lower level, for every dir */
3898#endif
3899 if (Showmode) {
3900 IH_RELEASE(h)(ih_release(h), (h)=((void *)0), 0);
3901 return 0;
3902 }
3903
3904 if (!rootdirfound && (orphans == ORPH_ATTACH2) && !Testing) {
3905
3906 Log("Cannot find root directory for volume %lu; attempting to create "
3907 "a new one\n", afs_printable_uint32_lu(vid));
3908
3909 code = CreateRootDir(salvinfo, &volHeader, alinkH, vid, &rootdir,
3910 &maxunique);
3911 if (code == 0) {
3912 rootdirfound = 1;
3913 newrootdir = 1;
3914 salvinfo->VolumeChanged = 1;
3915 }
3916 }
3917
3918 /* Parse each vnode looking for orphaned vnodes and
3919 * connect them to the tree as orphaned (if requested).
3920 */
3921 oldrootdir = rootdir;
3922 for (class = 0; class < nVNODECLASSES(((1<<1)-1)+1); class++) {
3923 for (v = 0; v < salvinfo->vnodeInfo[class].nVnodes; v++) {
3924 vep = &(salvinfo->vnodeInfo[class].vnodes[v]);
3925 ThisVnode = bitNumberToVnodeNumber(v, class)((VnodeId)(((v)<<1)+(class)+1));
3926 ThisUnique = vep->unique;
3927
3928 if ((vep->type == 0) || vep->claimed || ThisVnode == 1)
3929 continue; /* Ignore unused, claimed, and root vnodes */
3930
3931 /* This vnode is orphaned. If it is a directory vnode, then the '..'
3932 * entry in this vnode had incremented the parent link count (In
3933 * JudgeEntry()). We need to go to the parent and decrement that
3934 * link count. But if the parent's unique is zero, then the parent
3935 * link count was not incremented in JudgeEntry().
3936 */
3937 if (class == vLarge0) { /* directory vnode */
3938 pv = vnodeIdToBitNumber(vep->parent)(((vep->parent)-1)>>1);
3939 if (salvinfo->vnodeInfo[vLarge0].vnodes[pv].unique != 0) {
3940 if (vep->parent == 1 && newrootdir) {
3941 /* this vnode's parent was the volume root, and
3942 * we just created the volume root. So, the parent
3943 * dir didn't exist during JudgeEntry, so the link
3944 * count was not inc'd there, so don't dec it here.
3945 */
3946
3947 /* noop */
3948
3949 } else {
3950 salvinfo->vnodeInfo[vLarge0].vnodes[pv].count++;
3951 }
3952 }
3953 }
3954
3955 if (!rootdirfound)
3956 continue; /* If no rootdir, can't attach orphaned files */
3957
3958 /* Here we attach orphaned files and directories into the
3959 * root directory, LVVnode, making sure link counts stay correct.
3960 */
3961 if ((orphans == ORPH_ATTACH2) && !vep->todelete && !Testing) {
3962 LFVnode = rootdir.vnodeNumber; /* Lost+Found vnode number */
3963 LFUnique = rootdir.unique; /* Lost+Found uniquifier */
3964
3965 /* Update this orphaned vnode's info. Its parent info and
3966 * link count (do for orphaned directories and files).
3967 */
3968 vep->parent = LFVnode; /* Parent is the root dir */
3969 vep->unique = LFUnique;
3970 vep->changed = 1;
3971 vep->claimed = 1;
3972 vep->count--; /* Inc link count (root dir will pt to it) */
3973
3974 /* If this orphaned vnode is a directory, change '..'.
3975 * The name of the orphaned dir/file is unknown, so we
3976 * build a unique name. No need to CopyOnWrite the directory
3977 * since it is not connected to tree in BK or RO volume and
3978 * won't be visible there.
3979 */
3980 if (class == vLarge0) {
3981 AFSFid pa;
3982 DirHandle dh;
3983
3984 /* Remove and recreate the ".." entry in this orphaned directory */
3985 SetSalvageDirHandle(&dh, vid, salvinfo->fileSysDevice,
3986 salvinfo->vnodeInfo[class].inodes[v],
3987 &salvinfo->VolumeChanged);
3988 pa.Vnode = LFVnode;
3989 pa.Unique = LFUnique;
3990 osi_Assert(afs_dir_Delete(&dh, "..") == 0)(void)((afs_dir_Delete(&dh, "..") == 0) || (osi_AssertFailU
("afs_dir_Delete(&dh, \"..\") == 0", "./../vol/vol-salvage.c"
, 3990), 0))
;
3991 osi_Assert(afs_dir_Create(&dh, "..", &pa) == 0)(void)((afs_dir_Create(&dh, "..", &pa) == 0) || (osi_AssertFailU
("afs_dir_Create(&dh, \"..\", &pa) == 0", "./../vol/vol-salvage.c"
, 3991), 0))
;
3992
3993 /* The original parent's link count was decremented above.
3994 * Here we increment the new parent's link count.
3995 */
3996 pv = vnodeIdToBitNumber(LFVnode)(((LFVnode)-1)>>1);
3997 salvinfo->vnodeInfo[vLarge0].vnodes[pv].count--;
3998
3999 }
4000
4001 /* Go to the root dir and add this entry. The link count of the
4002 * root dir was incremented when ".." was created. Try 10 times.
4003 */
4004 for (j = 0; j < 10; j++) {
4005 pa.Vnode = ThisVnode;
4006 pa.Unique = ThisUnique;
4007
4008 snprintf(npath, sizeof npath, "%s.%u.%u",
4009 ((class == vLarge0) ? "__ORPHANDIR__"
4010 : "__ORPHANFILE__"),
4011 ThisVnode, ThisUnique);
4012
4013 CopyOnWrite(salvinfo, &rootdir);
4014 code = afs_dir_Create(&rootdir.dirHandle, npath, &pa);
4015 if (!code)
4016 break;
4017
4018 ThisUnique += 50; /* Try creating a different file */
4019 }
4020 osi_Assert(code == 0)(void)((code == 0) || (osi_AssertFailU("code == 0", "./../vol/vol-salvage.c"
, 4020), 0))
;
4021 Log("Attaching orphaned %s to volume's root dir as %s\n",
4022 ((class == vLarge0) ? "directory" : "file"), npath);
4023 }
4024 } /* for each vnode in the class */
4025 } /* for each class of vnode */
4026
4027 /* Delete the old rootinode directory if the rootdir was CopyOnWrite */
4028 DFlush();
4029 if (rootdirfound && !oldrootdir.copied && rootdir.copied) {
4030 code =
4031 IH_DEC(oldrootdir.ds_linkH, oldrootdir.dirHandle.dirh_inode,namei_dec(oldrootdir.ds_linkH, oldrootdir.dirHandle.dirh_inode
, oldrootdir.rwVid)
4032 oldrootdir.rwVid)namei_dec(oldrootdir.ds_linkH, oldrootdir.dirHandle.dirh_inode
, oldrootdir.rwVid)
;
4033 osi_Assert(code == 0)(void)((code == 0) || (osi_AssertFailU("code == 0", "./../vol/vol-salvage.c"
, 4033), 0))
;
4034 /* dirVnodeInfo->inodes[?] is not updated with new inode number */
4035 }
4036
4037 DFlush(); /* Flush the changes */
4038 if (!rootdirfound && (orphans == ORPH_ATTACH2)) {
4039 Log("Cannot attach orphaned files and directories: Root directory not found\n");
4040 orphans = ORPH_IGNORE0;
4041 }
4042
4043 /* Write out all changed vnodes. Orphaned files and directories
4044 * will get removed here also (if requested).
4045 */
4046 for (class = 0; class < nVNODECLASSES(((1<<1)-1)+1); class++) {
4047 afs_sfsize_t nVnodes = salvinfo->vnodeInfo[class].nVnodes;
4048 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
4049 struct VnodeEssence *vnodes = salvinfo->vnodeInfo[class].vnodes;
4050 FilesInVolume += salvinfo->vnodeInfo[class].nAllocatedVnodes;
4051 BlocksInVolume += salvinfo->vnodeInfo[class].volumeBlockCount;
4052 for (i = 0; i < nVnodes; i++) {
4053 struct VnodeEssence *vnp = &vnodes[i];
4054 VnodeId vnodeNumber = bitNumberToVnodeNumber(i, class)((VnodeId)(((i)<<1)+(class)+1));
4055
4056 /* If the vnode is good but is unclaimed (not listed in
4057 * any directory entries), then it is orphaned.
4058 */
4059 orphaned = -1;
4060 if ((vnp->type != 0) && (orphaned = IsVnodeOrphaned(salvinfo, vnodeNumber))) {
4061 vnp->claimed = 0; /* Makes IsVnodeOrphaned calls faster */
4062 vnp->changed = 1;
4063 }
4064
4065 if (vnp->changed || vnp->count) {
4066 int oldCount;
4067 nBytes =
4068 IH_IREAD(salvinfo->vnodeInfo[class].handle,namei_iread(salvinfo->vnodeInfo[class].handle, (((((vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
4069 vnodeIndexOffset(vcp, vnodeNumber),namei_iread(salvinfo->vnodeInfo[class].handle, (((((vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
4070 (char *)&vnode, sizeof(vnode))namei_iread(salvinfo->vnodeInfo[class].handle, (((((vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
;
4071 osi_Assert(nBytes == sizeof(vnode))(void)((nBytes == sizeof(vnode)) || (osi_AssertFailU("nBytes == sizeof(vnode)"
, "./../vol/vol-salvage.c", 4071), 0))
;
4072
4073 vnode.parent = vnp->parent;
4074 oldCount = vnode.linkCount;
4075 vnode.linkCount = vnode.linkCount - vnp->count;
4076
4077 if (orphaned == -1)
4078 orphaned = IsVnodeOrphaned(salvinfo, vnodeNumber);
4079 if (orphaned) {
4080 if (!vnp->todelete) {
4081 /* Orphans should have already been attached (if requested) */
4082 osi_Assert(orphans != ORPH_ATTACH)(void)((orphans != 2) || (osi_AssertFailU("orphans != ORPH_ATTACH"
, "./../vol/vol-salvage.c", 4082), 0))
;
4083 oblocks += vnp->blockCount;
4084 ofiles++;
4085 }
4086 if (((orphans == ORPH_REMOVE1) || vnp->todelete)
4087 && !Testing) {
4088 BlocksInVolume -= vnp->blockCount;
4089 FilesInVolume--;
4090 if (VNDISK_GET_INO(&vnode)((Inode)((&vnode)->vn_ino_lo | ((&vnode)->vn_ino_hi
? (((Inode)(&vnode)->vn_ino_hi)<<32) : 0)))
) {
4091 code =
4092 IH_DEC(alinkH, VNDISK_GET_INO(&vnode), vid)namei_dec(alinkH, ((Inode)((&vnode)->vn_ino_lo | ((&
vnode)->vn_ino_hi ? (((Inode)(&vnode)->vn_ino_hi)<<
32) : 0))), vid)
;
4093 osi_Assert(code == 0)(void)((code == 0) || (osi_AssertFailU("code == 0", "./../vol/vol-salvage.c"
, 4093), 0))
;
4094 }
4095 memset(&vnode, 0, sizeof(vnode));
4096 }
4097 } else if (vnp->count) {
4098 if (!Showmode) {
4099 Log("Vnode %u: link count incorrect (was %d, %s %d)\n", vnodeNumber, oldCount, (Testing ? "would have changed to" : "now"), vnode.linkCount);
4100 }
4101 } else {
4102 vnode.modeBits = vnp->modeBits;
4103 }
4104
4105 vnode.dataVersion++;
4106 if (!Testing) {
4107 nBytes =
4108 IH_IWRITE(salvinfo->vnodeInfo[class].handle,namei_iwrite(salvinfo->vnodeInfo[class].handle, (((((vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
4109 vnodeIndexOffset(vcp, vnodeNumber),namei_iwrite(salvinfo->vnodeInfo[class].handle, (((((vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
4110 (char *)&vnode, sizeof(vnode))namei_iwrite(salvinfo->vnodeInfo[class].handle, (((((vnodeNumber
)-1)>>1)+1)<<(vcp)->logSize), (char *)&vnode
, sizeof(vnode))
;
4111 osi_Assert(nBytes == sizeof(vnode))(void)((nBytes == sizeof(vnode)) || (osi_AssertFailU("nBytes == sizeof(vnode)"
, "./../vol/vol-salvage.c", 4111), 0))
;
4112 }
4113 salvinfo->VolumeChanged = 1;
4114 }
4115 }
4116 }
4117 if (!Showmode && ofiles) {
4118 Log("%s %d orphaned files and directories (approx. %u KB)\n",
4119 (!Testing
4120 && (orphans == ORPH_REMOVE1)) ? "Removed" : "Found", ofiles,
4121 oblocks);
4122 }
4123
4124 for (class = 0; class < nVNODECLASSES(((1<<1)-1)+1); class++) {
4125 struct VnodeInfo *vip = &salvinfo->vnodeInfo[class];
4126 for (i = 0; i < vip->nVnodes; i++)
4127 if (vip->vnodes[i].name)
4128 free(vip->vnodes[i].name);
4129 if (vip->vnodes)
4130 free(vip->vnodes);
4131 if (vip->inodes)
4132 free(vip->inodes);
4133 }
4134
4135 /* Set correct resource utilization statistics */
4136 volHeader.filecount = FilesInVolume;
4137 volHeader.diskused = BlocksInVolume;
4138
4139 /* Make sure the uniquifer is big enough: maxunique is the real maxUniquifier */
4140 if (volHeader.uniquifier < (maxunique + 1)) {
4141 if (!Showmode)
4142 Log("Volume uniquifier is too low; fixed\n");
4143 /* Plus 2,000 in case there are workstations out there with
4144 * cached vnodes that have since been deleted
4145 */
4146 volHeader.uniquifier = (maxunique + 1 + 2000);
4147 }
4148
4149 if (newrootdir) {
4150 Log("*** WARNING: Root directory recreated, but volume is fragile! "
4151 "Only use this salvaged volume to copy data to another volume; "
4152 "do not continue to use this volume (%lu) as-is.\n",
4153 afs_printable_uint32_lu(vid));
4154 }
4155
4156 if (!Testing && salvinfo->VolumeChanged) {
4157#ifdef FSSYNC_BUILD_CLIENT1
4158 if (salvinfo->useFSYNC) {
4159 afs_int32 fsync_code;
4160
4161 fsync_code = FSYNC_VolOp(vid, NULL((void *)0), FSYNC_VOL_BREAKCBKS, FSYNC_SALVAGE, NULL((void *)0));
4162 if (fsync_code) {
4163 Log("Error trying to tell the fileserver to break callbacks for "
4164 "changed volume %lu; error code %ld\n",
4165 afs_printable_uint32_lu(vid),
4166 afs_printable_int32_ld(fsync_code));
4167 } else {
4168 salvinfo->VolumeChanged = 0;
4169 }
4170 }
4171#endif /* FSSYNC_BUILD_CLIENT */
4172
4173#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
4174 if (!salvinfo->useFSYNC) {
4175 /* A volume's contents have changed, but the fileserver will not
4176 * break callbacks on the volume until it tries to load the vol
4177 * header. So, to reduce the amount of time a client could have
4178 * stale data, remove fsstate.dat, so the fileserver will init
4179 * callback state with all clients. This is a very coarse hammer,
4180 * and in the future we should just record which volumes have
4181 * changed. */
4182 code = unlink(AFSDIR_SERVER_FSSTATE_FILEPATHgetDirPath(AFSDIR_SERVER_FSSTATE_FILEPATH_ID));
4183 if (code && errno(* __error()) != ENOENT2) {
4184 Log("Error %d when trying to unlink FS state file %s\n", errno(* __error()),
4185 AFSDIR_SERVER_FSSTATE_FILEPATHgetDirPath(AFSDIR_SERVER_FSSTATE_FILEPATH_ID));
4186 }
4187 }
4188#endif
4189 }
4190
4191 /* Turn off the inUse bit; the volume's been salvaged! */
4192 volHeader.inUse = 0; /* clear flag indicating inUse@last crash */
4193 volHeader.needsSalvaged = 0; /* clear 'damaged' flag */
4194 volHeader.inService = 1; /* allow service again */
4195 volHeader.needsCallback = (salvinfo->VolumeChanged != 0);
4196 volHeader.dontSalvage = DONT_SALVAGE0xE5;
4197 salvinfo->VolumeChanged = 0;
4198 if (!Testing) {
4199 nBytes = IH_IWRITE(h, 0, (char *)&volHeader, sizeof(volHeader))namei_iwrite(h, 0, (char *)&volHeader, sizeof(volHeader));
4200 osi_Assert(nBytes == sizeof(volHeader))(void)((nBytes == sizeof(volHeader)) || (osi_AssertFailU("nBytes == sizeof(volHeader)"
, "./../vol/vol-salvage.c", 4200), 0))
;
4201 }
4202 if (!Showmode) {
4203 Log("%sSalvaged %s (%u): %d files, %d blocks\n",
4204 (Testing ? "It would have " : ""), volHeader.name, volHeader.id,
4205 FilesInVolume, BlocksInVolume);
4206 }
4207
4208 IH_RELEASE(salvinfo->vnodeInfo[vSmall].handle)(ih_release(salvinfo->vnodeInfo[1].handle), (salvinfo->
vnodeInfo[1].handle)=((void *)0), 0)
;
4209 IH_RELEASE(salvinfo->vnodeInfo[vLarge].handle)(ih_release(salvinfo->vnodeInfo[0].handle), (salvinfo->
vnodeInfo[0].handle)=((void *)0), 0)
;
4210 IH_RELEASE(h)(ih_release(h), (h)=((void *)0), 0);
4211 return 0;
4212}
4213
4214void
4215ClearROInUseBit(struct VolumeSummary *summary)
4216{
4217 IHandle_t *h = summary->volumeInfoHandle;
4218 afs_sfsize_t nBytes;
4219
4220 VolumeDiskData volHeader;
4221
4222 nBytes = IH_IREAD(h, 0, (char *)&volHeader, sizeof(volHeader))namei_iread(h, 0, (char *)&volHeader, sizeof(volHeader));
4223 osi_Assert(nBytes == sizeof(volHeader))(void)((nBytes == sizeof(volHeader)) || (osi_AssertFailU("nBytes == sizeof(volHeader)"
, "./../vol/vol-salvage.c", 4223), 0))
;
4224 osi_Assert(volHeader.stamp.magic == VOLUMEINFOMAGIC)(void)((volHeader.stamp.magic == ((bit32)0x78a1b2c5)) || (osi_AssertFailU
("volHeader.stamp.magic == VOLUMEINFOMAGIC", "./../vol/vol-salvage.c"
, 4224), 0))
;
4225 volHeader.inUse = 0;
4226 volHeader.needsSalvaged = 0;
4227 volHeader.inService = 1;
4228 volHeader.dontSalvage = DONT_SALVAGE0xE5;
4229 if (!Testing) {
4230 nBytes = IH_IWRITE(h, 0, (char *)&volHeader, sizeof(volHeader))namei_iwrite(h, 0, (char *)&volHeader, sizeof(volHeader));
4231 osi_Assert(nBytes == sizeof(volHeader))(void)((nBytes == sizeof(volHeader)) || (osi_AssertFailU("nBytes == sizeof(volHeader)"
, "./../vol/vol-salvage.c", 4231), 0))
;
4232 }
4233}
4234
4235/* MaybeZapVolume
4236 * Possible delete the volume.
4237 *
4238 * deleteMe - Always do so, only a partial volume.
4239 */
4240void
4241MaybeZapVolume(struct SalvInfo *salvinfo, struct InodeSummary *isp,
4242 char *message, int deleteMe, int check)
4243{
4244 if (readOnly(isp)((isp)->volumeId != (isp)->RWvolumeId) || deleteMe) {
4245 if (isp->volSummary && isp->volSummary->fileName) {
4246 if (deleteMe) {
4247 if (!Showmode)
4248 Log("Volume %u (is only a partial volume--probably an attempt was made to move/restore it when a machine crash occured.\n", isp->volumeId);
4249 if (!Showmode)
4250 Log("It will be deleted on this server (you may find it elsewhere)\n");
4251 } else {
4252 if (!Showmode)
4253 Log("Volume %u needs to be salvaged. Since it is read-only, however,\n", isp->volumeId);
4254 if (!Showmode)
4255 Log("it will be deleted instead. It should be recloned.\n");
4256 }
4257 if (!Testing) {
4258 afs_int32 code;
4259 char path[64];
4260 sprintf(path, "%s" OS_DIRSEP"/" "%s", salvinfo->fileSysPath, isp->volSummary->fileName);
4261
4262 code = VDestroyVolumeDiskHeader(salvinfo->fileSysPartition, isp->volumeId, isp->RWvolumeId);
4263 if (code) {
4264 Log("Error %ld destroying volume disk header for volume %lu\n",
4265 afs_printable_int32_ld(code),
4266 afs_printable_uint32_lu(isp->volumeId));
4267 }
4268
4269 /* make sure we actually delete the fileName file; ENOENT
4270 * is fine, since VDestroyVolumeDiskHeader probably already
4271 * unlinked it */
4272 if (unlink(path) && errno(* __error()) != ENOENT2) {
4273 Log("Unable to unlink %s (errno = %d)\n", path, errno(* __error()));
4274 }
4275 if (salvinfo->useFSYNC) {
4276 AskDelete(salvinfo, isp->volumeId);
4277 }
4278 isp->volSummary->deleted = 1;
4279 }
4280 }
4281 } else if (!check) {
4282 Log("%s salvage was unsuccessful: read-write volume %u\n", message,
4283 isp->volumeId);
4284 Abort("Salvage of volume %u aborted\n", isp->volumeId);
4285 }
4286}
4287
4288#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
4289/**
4290 * Locks a volume on disk for salvaging.
4291 *
4292 * @param[in] volumeId volume ID to lock
4293 *
4294 * @return operation status
4295 * @retval 0 success
4296 * @retval -1 volume lock raced with a fileserver restart; all volumes must
4297 * checked out and locked again
4298 *
4299 * @note DAFS only
4300 */
4301static int
4302LockVolume(struct SalvInfo *salvinfo, VolumeId volumeId)
4303{
4304 afs_int32 code;
4305 int locktype;
4306
4307 /* should always be WRITE_LOCK, but keep the lock-type logic all
4308 * in one place, in VVolLockType. Params will be ignored, but
4309 * try to provide what we're logically doing. */
4310 locktype = VVolLockType(V_VOLUPD3, 1);
4311
4312 code = VLockVolumeByIdNB(volumeId, salvinfo->fileSysPartition, locktype);
4313 if (code) {
4314 if (code == EBUSY16) {
4315 Abort("Someone else appears to be using volume %lu; Aborted\n",
4316 afs_printable_uint32_lu(volumeId));
4317 }
4318 Abort("Error %ld trying to lock volume %lu; Aborted\n",
4319 afs_printable_int32_ld(code),
4320 afs_printable_uint32_lu(volumeId));
4321 }
4322
4323 code = FSYNC_VerifyCheckout(volumeId, salvinfo->fileSysPathName, FSYNC_VOL_OFF, FSYNC_SALVAGE);
4324 if (code == SYNC_DENIED) {
4325 /* need to retry checking out volumes */
4326 return -1;
4327 }
4328 if (code != SYNC_OK) {
4329 Abort("FSYNC_VerifyCheckout failed for volume %lu with code %ld\n",
4330 afs_printable_uint32_lu(volumeId), afs_printable_int32_ld(code));
4331 }
4332
4333 /* set inUse = programType in the volume header to ensure that nobody
4334 * tries to use this volume again without salvaging, if we somehow crash
4335 * or otherwise exit before finishing the salvage.
4336 */
4337 if (!Testing) {
4338 IHandle_t *h;
4339 struct VolumeHeader header;
4340 struct VolumeDiskHeader diskHeader;
4341 struct VolumeDiskData volHeader;
4342
4343 code = VReadVolumeDiskHeader(volumeId, salvinfo->fileSysPartition, &diskHeader);
4344 if (code) {
4345 return 0;
4346 }
4347
4348 DiskToVolumeHeader(&header, &diskHeader);
4349
4350 IH_INIT(h, salvinfo->fileSysDevice, header.parent, header.volumeInfo)((h) = ih_init((salvinfo->fileSysDevice), (header.parent),
(header.volumeInfo)))
;
4351 if (IH_IREAD(h, 0, (char*)&volHeader, sizeof(volHeader))namei_iread(h, 0, (char*)&volHeader, sizeof(volHeader)) != sizeof(volHeader) ||
4352 volHeader.stamp.magic != VOLUMEINFOMAGIC((bit32)0x78a1b2c5)) {
4353
4354 IH_RELEASE(h)(ih_release(h), (h)=((void *)0), 0);
4355 return 0;
4356 }
4357
4358 volHeader.inUse = programType;
4359
4360 /* If we can't re-write the header, bail out and error. We don't
4361 * assert when reading the header, since it's possible the
4362 * header isn't really there (when there's no data associated
4363 * with the volume; we just delete the vol header file in that
4364 * case). But if it's there enough that we can read it, but
4365 * somehow we cannot write to it to signify we're salvaging it,
4366 * we've got a big problem and we cannot continue. */
4367 osi_Assert(IH_IWRITE(h, 0, (char*)&volHeader, sizeof(volHeader)) == sizeof(volHeader))(void)((namei_iwrite(h, 0, (char*)&volHeader, sizeof(volHeader
)) == sizeof(volHeader)) || (osi_AssertFailU("IH_IWRITE(h, 0, (char*)&volHeader, sizeof(volHeader)) == sizeof(volHeader)"
, "./../vol/vol-salvage.c", 4367), 0))
;
4368
4369 IH_RELEASE(h)(ih_release(h), (h)=((void *)0), 0);
4370 }
4371
4372 return 0;
4373}
4374#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
4375
4376static void
4377AskError(struct SalvInfo *salvinfo, VolumeId volumeId)
4378{
4379#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
4380 afs_int32 code;
4381 code = FSYNC_VolOp(volumeId, salvinfo->fileSysPartition->name,
4382 FSYNC_VOL_FORCE_ERROR, FSYNC_WHATEVER, NULL((void *)0));
4383 if (code != SYNC_OK) {
4384 Log("AskError: failed to force volume %lu into error state; "
4385 "SYNC error code %ld (%s)\n", (long unsigned)volumeId,
4386 (long)code, SYNC_res2string(code));
4387 }
4388#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
4389}
4390
4391void
4392AskOffline(struct SalvInfo *salvinfo, VolumeId volumeId)
4393{
4394 afs_int32 code, i;
4395 SYNC_response res;
4396
4397 memset(&res, 0, sizeof(res));
4398
4399 for (i = 0; i < 3; i++) {
4400 code = FSYNC_VolOp(volumeId, salvinfo->fileSysPartition->name,
4401 FSYNC_VOL_OFF, FSYNC_SALVAGE, &res);
4402
4403 if (code == SYNC_OK) {
4404 break;
4405 } else if (code == SYNC_DENIED) {
4406 if (AskDAFS())
4407 Log("AskOffline: file server denied offline request; a general salvage may be required.\n");
4408 else
4409 Log("AskOffline: file server denied offline request; a general salvage is required.\n");
4410 Abort("Salvage aborted\n");
4411 } else if (code == SYNC_BAD_COMMAND) {
4412 Log("AskOffline: fssync protocol mismatch (bad command word '%d'); salvage aborting.\n",
4413 FSYNC_VOL_OFF);
4414 if (AskDAFS()) {
4415#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
4416 Log("AskOffline: please make sure dafileserver, davolserver, salvageserver and dasalvager binaries are same version.\n");
4417#else
4418 Log("AskOffline: fileserver is DAFS but we are not.\n");
4419#endif
4420 } else {
4421#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
4422 Log("AskOffline: fileserver is not DAFS but we are.\n");
4423#else
4424 Log("AskOffline: please make sure fileserver, volserver and salvager binaries are same version.\n");
4425#endif
4426 }
4427 Abort("Salvage aborted\n");
4428 } else if (i < 2) {
4429 /* try it again */
4430 Log("AskOffline: request for fileserver to take volume offline failed; trying again...\n");
4431 FSYNC_clientFinis();
4432 FSYNC_clientInit();
4433 }
4434 }
4435 if (code != SYNC_OK) {
4436 Log("AskOffline: request for fileserver to take volume offline failed; salvage aborting.\n");
4437 Abort("Salvage aborted\n");
4438 }
4439}
4440
4441/* don't want to pass around state; remember it here */
4442static int isDAFS = -1;
4443int
4444AskDAFS(void)
4445{
4446 afs_int32 code, i, ret = 0;
4447 SYNC_response res;
4448
4449 /* we don't care if we race. the answer shouldn't change */
4450 if (isDAFS != -1)
4451 return isDAFS;
4452
4453 memset(&res, 0, sizeof(res));
4454
4455 for (i = 0; i < 3; i++) {
4456 code = FSYNC_VolOp(1, NULL((void *)0),
4457 FSYNC_VOL_QUERY_VOP, FSYNC_SALVAGE, &res);
4458
4459 if (code == SYNC_OK) {
4460 ret = 1;
4461 break;
4462 } else if (code == SYNC_DENIED) {
4463 ret = 1;
4464 break;
4465 } else if (code == SYNC_BAD_COMMAND) {
4466 ret = 0;
4467 break;
4468 } else if (code == SYNC_FAILED) {
4469 if (res.hdr.reason == FSYNC_UNKNOWN_VOLID)
4470 ret = 1;
4471 else
4472 ret = 0;
4473 break;
4474 } else if (i < 2) {
4475 /* try it again */
4476 Log("AskDAFS: request to query fileserver failed; trying again...\n");
4477 FSYNC_clientFinis();
4478 FSYNC_clientInit();
4479 }
4480 }
4481
4482 isDAFS = ret;
4483 return ret;
4484}
4485
4486static void
4487MaybeAskOnline(struct SalvInfo *salvinfo, VolumeId volumeId)
4488{
4489 struct VolumeDiskHeader diskHdr;
4490 int code;
4491 code = VReadVolumeDiskHeader(volumeId, salvinfo->fileSysPartition, &diskHdr);
4492 if (code) {
4493 /* volume probably does not exist; no need to bring back online */
4494 return;
4495 }
4496 AskOnline(salvinfo, volumeId);
4497}
4498
4499void
4500AskOnline(struct SalvInfo *salvinfo, VolumeId volumeId)
4501{
4502 afs_int32 code, i;
4503
4504 for (i = 0; i < 3; i++) {
4505 code = FSYNC_VolOp(volumeId, salvinfo->fileSysPartition->name,
4506 FSYNC_VOL_ON, FSYNC_WHATEVER, NULL((void *)0));
4507
4508 if (code == SYNC_OK) {
4509 break;
4510 } else if (code == SYNC_DENIED) {
4511 Log("AskOnline: file server denied online request to volume %u partition %s; trying again...\n", volumeId, salvinfo->fileSysPartition->name);
4512 } else if (code == SYNC_BAD_COMMAND) {
4513 Log("AskOnline: fssync protocol mismatch (bad command word '%d')\n",
4514 FSYNC_VOL_ON);
4515 Log("AskOnline: please make sure file server binaries are same version.\n");
4516 break;
4517 } else if (i < 2) {
4518 /* try it again */
4519 Log("AskOnline: request for fileserver to put volume online failed; trying again...\n");
4520 FSYNC_clientFinis();
4521 FSYNC_clientInit();
4522 }
4523 }
4524}
4525
4526void
4527AskDelete(struct SalvInfo *salvinfo, VolumeId volumeId)
4528{
4529 afs_int32 code, i;
4530 SYNC_response res;
4531
4532 for (i = 0; i < 3; i++) {
4533 memset(&res, 0, sizeof(res));
4534 code = FSYNC_VolOp(volumeId, salvinfo->fileSysPartition->name,
4535 FSYNC_VOL_DONE, FSYNC_SALVAGE, &res);
4536
4537 if (code == SYNC_OK) {
4538 break;
4539 } else if (code == SYNC_DENIED) {
4540 Log("AskOnline: file server denied DONE request to volume %u partition %s; trying again...\n", volumeId, salvinfo->fileSysPartition->name);
4541 } else if (code == SYNC_BAD_COMMAND) {
4542 Log("AskOnline: fssync protocol mismatch (bad command word '%d')\n",
4543 FSYNC_VOL_DONE);
4544 if (AskDAFS()) {
4545#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
4546 Log("AskOnline: please make sure dafileserver, davolserver, salvageserver and dasalvager binaries are same version.\n");
4547#else
4548 Log("AskOnline: fileserver is DAFS but we are not.\n");
4549#endif
4550 } else {
4551#if defined(AFS_DEMAND_ATTACH_FS1) || defined(AFS_DEMAND_ATTACH_UTIL)
4552 Log("AskOnline: fileserver is not DAFS but we are.\n");
4553#else
4554 Log("AskOnline: please make sure fileserver, volserver and salvager binaries are same version.\n");
4555#endif
4556 }
4557 break;
4558 } else if (code == SYNC_FAILED &&
4559 (res.hdr.reason == FSYNC_UNKNOWN_VOLID ||
4560 res.hdr.reason == FSYNC_WRONG_PART)) {
4561 /* volume is already effectively 'deleted' */
4562 break;
4563 } else if (i < 2) {
4564 /* try it again */
4565 Log("AskOnline: request for fileserver to delete volume failed; trying again...\n");
4566 FSYNC_clientFinis();
4567 FSYNC_clientInit();
4568 }
4569 }
4570}
4571
4572int
4573CopyInode(Device device, Inode inode1, Inode inode2, int rwvolume)
4574{
4575 /* Volume parameter is passed in case iopen is upgraded in future to
4576 * require a volume Id to be passed
4577 */
4578 char buf[4096];
4579 IHandle_t *srcH, *destH;
4580 FdHandle_t *srcFdP, *destFdP;
4581 ssize_t nBytes = 0;
4582 afs_foff_t size = 0;
4583
4584 IH_INIT(srcH, device, rwvolume, inode1)((srcH) = ih_init((device), (rwvolume), (inode1)));
4585 srcFdP = IH_OPEN(srcH)ih_open(srcH);
4586 osi_Assert(srcFdP != NULL)(void)((srcFdP != ((void *)0)) || (osi_AssertFailU("srcFdP != NULL"
, "./../vol/vol-salvage.c", 4586), 0))
;
4587 IH_INIT(destH, device, rwvolume, inode2)((destH) = ih_init((device), (rwvolume), (inode2)));
4588 destFdP = IH_OPEN(destH)ih_open(destH);
4589 while ((nBytes = FDH_PREAD(srcFdP, buf, sizeof(buf), size)pread((srcFdP)->fd_fd, buf, sizeof(buf), size)) > 0) {
4590 osi_Assert(FDH_PWRITE(destFdP, buf, nBytes, size) == nBytes)(void)((pwrite((destFdP)->fd_fd, buf, nBytes, size) == nBytes
) || (osi_AssertFailU("FDH_PWRITE(destFdP, buf, nBytes, size) == nBytes"
, "./../vol/vol-salvage.c", 4590), 0))
;
4591 size += nBytes;
4592 }
4593 osi_Assert(nBytes == 0)(void)((nBytes == 0) || (osi_AssertFailU("nBytes == 0", "./../vol/vol-salvage.c"
, 4593), 0))
;
4594 FDH_REALLYCLOSE(srcFdP)(fd_reallyclose(srcFdP), (srcFdP)=((void *)0), 0);
4595 FDH_REALLYCLOSE(destFdP)(fd_reallyclose(destFdP), (destFdP)=((void *)0), 0);
4596 IH_RELEASE(srcH)(ih_release(srcH), (srcH)=((void *)0), 0);
4597 IH_RELEASE(destH)(ih_release(destH), (destH)=((void *)0), 0);
4598 return 0;
4599}
4600
4601void
4602PrintInodeList(struct SalvInfo *salvinfo)
4603{
4604 struct ViceInodeInfo *ip;
4605 struct ViceInodeInfo *buf;
4606 int nInodes;
4607 afs_ino_str_t stmp;
4608 afs_sfsize_t st_size;
4609
4610 st_size = OS_SIZE(salvinfo->inodeFd)ih_size(salvinfo->inodeFd);
4611 osi_Assert(st_size >= 0)(void)((st_size >= 0) || (osi_AssertFailU("st_size >= 0"
, "./../vol/vol-salvage.c", 4611), 0))
;
4612 buf = (struct ViceInodeInfo *)malloc(st_size);
4613 osi_Assert(buf != NULL)(void)((buf != ((void *)0)) || (osi_AssertFailU("buf != NULL"
, "./../vol/vol-salvage.c", 4613), 0))
;
4614 nInodes = st_size / sizeof(struct ViceInodeInfo);
4615 osi_Assert(OS_READ(salvinfo->inodeFd, buf, st_size) == st_size)(void)((read(salvinfo->inodeFd, buf, st_size) == st_size) ||
(osi_AssertFailU("OS_READ(salvinfo->inodeFd, buf, st_size) == st_size"
, "./../vol/vol-salvage.c", 4615), 0))
;
4616 for (ip = buf; nInodes--; ip++) {
4617 Log("Inode:%s, linkCount=%d, size=%#llx, p=(%u,%u,%u,%u)\n",
4618 PrintInode(stmp, ip->inodeNumber), ip->linkCount,
4619 (afs_uintmax_t) ip->byteCount, ip->u.param[0], ip->u.param[1],
4620 ip->u.param[2], ip->u.param[3]);
4621 }
4622 free(buf);
4623}
4624
4625void
4626PrintInodeSummary(struct SalvInfo *salvinfo)
4627{
4628 int i;
4629 struct InodeSummary *isp;
4630
4631 for (i = 0; i < salvinfo->nVolumesInInodeFile; i++) {
4632 isp = &salvinfo->inodeSummary[i];
4633 Log("VID:%u, RW:%u, index:%d, nInodes:%d, nSpecialInodes:%d, maxUniquifier:%u, volSummary\n", isp->volumeId, isp->RWvolumeId, isp->index, isp->nInodes, isp->nSpecialInodes, isp->maxUniquifier);
4634 }
4635}
4636
4637void
4638PrintVolumeSummary(struct SalvInfo *salvinfo)
4639{
4640 int i;
4641 struct VolumeSummary *vsp;
4642
4643 for (i = 0, vsp = salvinfo->volumeSummaryp; i < salvinfo->nVolumes; vsp++, i++) {
4644 Log("fileName:%s, header, wouldNeedCallback\n", vsp->fileName);
4645 }
4646}
4647
4648int
4649Fork(void)
4650{
4651 int f;
4652#ifdef AFS_NT40_ENV
4653 f = 0;
4654 osi_Assert(0)(void)((0) || (osi_AssertFailU("0", "./../vol/vol-salvage.c",
4654), 0))
; /* Fork is never executed in the NT code path */
4655#else
4656 f = fork();
4657 osi_Assert(f >= 0)(void)((f >= 0) || (osi_AssertFailU("f >= 0", "./../vol/vol-salvage.c"
, 4657), 0))
;
4658#ifdef AFS_DEMAND_ATTACH_FS1
4659 if ((f == 0) && (programType == salvageServer)) {
4660 /* we are a salvageserver child */
4661#ifdef FSSYNC_BUILD_CLIENT1
4662 VChildProcReconnectFS_r();
4663#endif
4664#ifdef SALVSYNC_BUILD_CLIENT1
4665 VReconnectSALV_r();
4666#endif
4667 }
4668#endif /* AFS_DEMAND_ATTACH_FS */
4669#endif /* !AFS_NT40_ENV */
4670 return f;
4671}
4672
4673void
4674Exit(int code)
4675{
4676 if (ShowLog)
4677 showlog();
4678
4679#ifdef AFS_DEMAND_ATTACH_FS1
4680 if (programType == salvageServer) {
4681#ifdef SALVSYNC_BUILD_CLIENT1
4682 VDisconnectSALV();
4683#endif
4684#ifdef FSSYNC_BUILD_CLIENT1
4685 VDisconnectFS();
4686#endif
4687 }
4688#endif /* AFS_DEMAND_ATTACH_FS */
4689
4690#ifdef AFS_NT40_ENV
4691 if (main_thread != pthread_self())
4692 pthread_exit((void *)code);
4693 else
4694 exit(code);
4695#else
4696 exit(code);
4697#endif
4698}
4699
4700int
4701Wait(char *prog)
4702{
4703 int status;
4704 int pid;
4705 pid = wait(&status);
4706 osi_Assert(pid != -1)(void)((pid != -1) || (osi_AssertFailU("pid != -1", "./../vol/vol-salvage.c"
, 4706), 0))
;
4707 if (WCOREDUMP(status)((status) & 0200))
4708 Log("\"%s\" core dumped!\n", prog);
4709 if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
!= 0 || WEXITSTATUS(status)((status) >> 8) != 0)
4710 return -1;
4711 return pid;
4712}
4713
4714static char *
4715TimeStamp(time_t clock, int precision)
4716{
4717 struct tm *lt;
4718 static char timestamp[20];
4719 lt = localtime(&clock);
4720 if (precision)
4721 (void)strftime(timestamp, 20, "%m/%d/%Y %H:%M:%S", lt);
4722 else
4723 (void)strftime(timestamp, 20, "%m/%d/%Y %H:%M", lt);
4724 return timestamp;
4725}
4726
4727void
4728CheckLogFile(char * log_path)
4729{
4730 char oldSlvgLog[AFSDIR_PATH_MAX256];
4731
4732#ifndef AFS_NT40_ENV
4733 if (useSyslog) {
4734 ShowLog = 0;
4735 return;
4736 }
4737#endif
4738
4739 strcpy(oldSlvgLog, log_path);
4740 strcat(oldSlvgLog, ".old");
4741 if (!logFile) {
4742 renamefile(log_path, oldSlvgLog);
4743 logFile = afs_fopenfopen(log_path, "a");
4744
4745 if (!logFile) { /* still nothing, use stdout */
4746 logFile = stdout__stdoutp;
4747 ShowLog = 0;
4748 }
4749#ifndef AFS_NAMEI_ENV1
4750 AFS_DEBUG_IOPS_LOG(logFile);
4751#endif
4752 }
4753}
4754
4755#ifndef AFS_NT40_ENV
4756void
4757TimeStampLogFile(char * log_path)
4758{
4759 char stampSlvgLog[AFSDIR_PATH_MAX256];
4760 struct tm *lt;
4761 time_t now;
4762
4763 now = time(0);
4764 lt = localtime(&now);
4765 snprintf(stampSlvgLog, sizeof stampSlvgLog,
4766 "%s.%04d-%02d-%02d.%02d:%02d:%02d", log_path,
4767 lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour,
4768 lt->tm_min, lt->tm_sec);
4769
4770 /* try to link the logfile to a timestamped filename */
4771 /* if it fails, oh well, nothing we can do */
4772 link(log_path, stampSlvgLog);
4773}
4774#endif
4775
4776void
4777showlog(void)
4778{
4779 char line[256];
4780
4781#ifndef AFS_NT40_ENV
4782 if (useSyslog) {
4783 printf("Can't show log since using syslog.\n");
4784 fflush(stdout__stdoutp);
4785 return;
4786 }
4787#endif
4788
4789 if (logFile) {
4790 rewind(logFile);
4791 fclose(logFile);
4792 }
4793
4794 logFile = afs_fopenfopen(AFSDIR_SERVER_SLVGLOG_FILEPATHgetDirPath(AFSDIR_SERVER_SLVGLOG_FILEPATH_ID), "r");
4795
4796 if (!logFile)
4797 printf("Can't read %s, exiting\n", AFSDIR_SERVER_SLVGLOG_FILEPATHgetDirPath(AFSDIR_SERVER_SLVGLOG_FILEPATH_ID));
4798 else {
4799 rewind(logFile);
4800 while (fgets(line, sizeof(line), logFile))
4801 printf("%s", line);
4802 fflush(stdout__stdoutp);
4803 }
4804}
4805
4806void
4807Log(const char *format, ...)
4808{
4809 struct timeval now;
4810 char tmp[1024];
4811 va_list args;
4812
4813 va_start(args, format)__builtin_va_start((args), (format));
4814 vsnprintf(tmp, sizeof tmp, format, args);
4815 va_end(args)__builtin_va_end(args);
4816#ifndef AFS_NT40_ENV
4817 if (useSyslog) {
4818 syslog(LOG_INFO6, "%s", tmp);
4819 } else
4820#endif
4821 if (logFile) {
4822 gettimeofday(&now, NULL((void *)0));
4823 fprintf(logFile, "%s %s", TimeStamp(now.tv_sec, 1), tmp);
4824 fflush(logFile);
4825 }
4826}
4827
4828void
4829Abort(const char *format, ...)
4830{
4831 va_list args;
4832 char tmp[1024];
4833
4834 va_start(args, format)__builtin_va_start((args), (format));
4835 vsnprintf(tmp, sizeof tmp, format, args);
4836 va_end(args)__builtin_va_end(args);
4837#ifndef AFS_NT40_ENV
4838 if (useSyslog) {
4839 syslog(LOG_INFO6, "%s", tmp);
4840 } else
4841#endif
4842 if (logFile) {
4843 fprintf(logFile, "%s", tmp);
4844 fflush(logFile);
4845 if (ShowLog)
4846 showlog();
4847 }
4848
4849 if (debug)
4850 abort();
4851 Exit(1);
4852}
4853
4854char *
4855ToString(const char *s)
4856{
4857 char *p;
4858 p = (char *)malloc(strlen(s) + 1);
4859 osi_Assert(p != NULL)(void)((p != ((void *)0)) || (osi_AssertFailU("p != NULL", "./../vol/vol-salvage.c"
, 4859), 0))
;
4860 strcpy(p, s);
4861 return p;
4862}
4863
4864/* Remove the FORCESALVAGE file */
4865void
4866RemoveTheForce(char *path)
4867{
4868 char target[1024];
4869 struct afs_stat_ststat force; /* so we can use afs_stat to find it */
4870 strcpy(target,path);
4871 strcat(target,"/FORCESALVAGE");
4872 if (!Testing && ForceSalvage) {
4873 if (afs_statstat(target,&force) == 0) unlink(target);
4874 }
4875}
4876
4877#ifndef AFS_AIX32_ENV
4878/*
4879 * UseTheForceLuke - see if we can use the force
4880 */
4881int
4882UseTheForceLuke(char *path)
4883{
4884 struct afs_stat_ststat force;
4885 char target[1024];
4886 strcpy(target,path);
4887 strcat(target,"/FORCESALVAGE");
4888
4889 return (afs_statstat(target, &force) == 0);
4890}
4891#else
4892/*
4893 * UseTheForceLuke - see if we can use the force
4894 *
4895 * NOTE:
4896 * The VRMIX fsck will not muck with the filesystem it is supposedly
4897 * fixing and create a "FORCESALVAGE" file (by design). Instead, we
4898 * muck directly with the root inode, which is within the normal
4899 * domain of fsck.
4900 * ListViceInodes() has a side effect of setting ForceSalvage if
4901 * it detects a need, based on root inode examination.
4902 */
4903int
4904UseTheForceLuke(char *path)
4905{
4906
4907 return 0; /* sorry OB1 */
4908}
4909#endif
4910
4911#ifdef AFS_NT40_ENV
4912/* NT support routines */
4913
4914static char execpathname[MAX_PATH];
4915int
4916nt_SalvagePartition(char *partName, int jobn)
4917{
4918 int pid;
4919 int n;
4920 childJob_t job;
4921 if (!*execpathname) {
4922 n = GetModuleFileName(NULL((void *)0), execpathname, MAX_PATH - 1);
4923 if (!n || n == 1023)
4924 return -1;
4925 }
4926 job.cj_magic = SALVAGER_MAGIC;
4927 job.cj_number = jobn;
4928 (void)strcpy(job.cj_part, partName);
4929 pid = (int)spawnprocveb(execpathname, save_args, NULL((void *)0), &job, sizeof(job));
4930 return pid;
4931}
4932
4933int
4934nt_SetupPartitionSalvage(void *datap, int len)
4935{
4936 childJob_t *jobp = (childJob_t *) datap;
4937 char logname[AFSDIR_PATH_MAX256];
4938
4939 if (len != sizeof(childJob_t))
4940 return -1;
4941 if (jobp->cj_magic != SALVAGER_MAGIC)
4942 return -1;
4943 myjob = *jobp;
4944
4945 /* Open logFile */
4946 (void)sprintf(logname, "%s.%d", AFSDIR_SERVER_SLVGLOG_FILEPATHgetDirPath(AFSDIR_SERVER_SLVGLOG_FILEPATH_ID),
4947 myjob.cj_number);
4948 logFile = afs_fopenfopen(logname, "w");
4949 if (!logFile)
4950 logFile = stdout__stdoutp;
4951
4952 return 0;
4953}
4954
4955
4956#endif /* AFS_NT40_ENV */