logging-changes-for-large-files-20030619
[openafs.git] / src / vol / nuke.c
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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID("$Header$");
14
15 #include <rx/xdr.h>
16 #include <afs/afsint.h>
17 #include <stdio.h>
18 #ifdef AFS_PTHREAD_ENV
19 #include <assert.h>
20 #else /* AFS_PTHREAD_ENV */
21 #include <afs/assert.h>
22 #endif /* AFS_PTHREAD_ENV */
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV)
27 #include <string.h>
28 #else
29 #include <strings.h>
30 #endif
31
32 #include <afs/assert.h>
33 #include "nfs.h"
34 #include "lwp.h"
35 #include "lock.h"
36 #include <afs/afssyscalls.h>
37 #include "ihandle.h"
38 #include "vnode.h"
39 #include "volume.h"
40 #include "partition.h"
41 #include "viceinode.h"
42 #include "salvage.h"
43 #include "fssync.h"
44
45 /*@printflike@*/ extern void Log(const char *format, ...);
46
47
48 struct Lock localLock;
49 char *vol_DevName();
50
51 #define MAXATONCE       100
52 /* structure containing neatly packed set of inodes and the # of times we'll have
53  * to idec them in order to reclaim their storage.  NukeProc, called by ListViceInodes,
54  * builds this list for us.
55  */
56 struct ilist {
57     struct ilist *next;
58     afs_int32 freePtr;                          /* first free index in this table */
59     Inode inode[MAXATONCE];                     /* inode # */
60     afs_int32 count[MAXATONCE];                 /* link count */
61 } *allInodes = 0;
62
63 /* called with a structure specifying info about the inode, and our rock (which
64  * is the volume ID.  Returns true if we should keep this inode, otherwise false.
65  * Note that ainfo->u.param[0] is always the volume ID, for any vice inode.
66  */
67 static int NukeProc(struct ViceInodeInfo *ainfo, afs_int32 avolid)
68 {
69     struct ilist *ti;
70     register afs_int32 i;
71
72 #ifndef AFS_PTHREAD_ENV
73     IOMGR_Poll();       /* poll so we don't kill the RPC connection */
74 #endif /* !AFS_PTHREAD_ENV */
75
76     /* check if this is the volume we're looking for */
77     if (ainfo->u.param[0] != avolid) return 0;  /* don't want this one */
78     /* record the info */
79     if (!allInodes || allInodes->freePtr >= MAXATONCE) {
80         ti = (struct ilist *) malloc(sizeof(struct ilist));
81         memset(ti, 0, sizeof(*ti));
82         ti->next = allInodes;
83         allInodes = ti;
84     }
85     else ti = allInodes;        /* use the one with space */
86     i = ti->freePtr++;  /* find our slot in this mess */
87     ti->inode[i] = ainfo->inodeNumber;
88     ti->count[i] = ainfo->linkCount;
89     return 0;   /* don't care if anything's written out, actually */
90 }
91
92 /* function called with partition name and volid ID, and which removes all
93  * inodes marked with the specified volume ID.  If the volume is a read-only
94  * clone, we'll only remove the header inodes, since they're the only inodes
95  * marked with that volume ID.  If you want to reclaim all the data, you should
96  * nuke the read-write volume ID.
97  *
98  * Note also that nuking a read-write volume effectively nukes all RO volumes
99  * cloned from that RW volume ID, too, since everything except for their
100  * indices will be gone.
101  */
102 int nuke(char *aname, afs_int32 avolid)
103 {
104     /* first process the partition containing this junk */
105     struct stat tstat;
106     struct ilist *ti, *ni;
107     register afs_int32 code;
108     char *tfile;
109     int i, j, forceSal;
110     char devName[64], wpath[100];
111     char *lastDevComp;
112 #ifdef AFS_NAMEI_ENV
113 #ifdef AFS_NT40_ENV
114     char path[MAX_PATH];
115 #else
116     char *path;
117     namei_t ufs_name;
118 #endif
119 #endif /* AFS_NAMEI_ENV */
120     IHandle_t *fileH;
121
122     if (avolid == 0) return EINVAL;
123     code = stat(aname, &tstat);
124     if (code) {
125         printf("volnuke: partition %s does not exist.\n", aname);
126         return code;
127     }
128     /* get the device name for the partition */
129 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
130     lastDevComp = aname;
131 #else
132 #ifdef AFS_NT40_ENV
133     lastDevComp = &aname[strlen(aname)-1];
134     *lastDevComp = toupper(*lastDevComp);
135 #else
136     tfile = vol_DevName(tstat.st_dev, wpath);
137     if (!tfile) {
138         printf("volnuke: can't find %s's device.\n", aname);
139         return 1;
140     }
141     strcpy(devName, tfile);     /* save this from the static buffer */
142     /* aim lastDevComp at the 'foo' of '/dev/foo' */
143     lastDevComp = strrchr(devName, '/');
144     /* either points at slash, or there is no slash; adjust appropriately */
145     if (lastDevComp)
146         lastDevComp++;
147     else lastDevComp = devName;
148 #endif /* AFS_NT40_ENV */
149 #endif /* AFS_NAMEI_ENV && !AFS_NT40_ENV */
150
151     ObtainWriteLock(&localLock);
152     /* OK, we have the mounted on place, aname, the device name (in devName).
153      * all we need to do to call ListViceInodes is find the inodes for the
154      * volume we're nuking.
155      */
156 #ifdef AFS_NAMEI_ENV
157     code = ListViceInodes(lastDevComp, aname, NULL, NukeProc, avolid,
158                           &forceSal, 0, wpath);
159 #else
160     code = ListViceInodes(lastDevComp, aname, "/tmp/vNukeXX", NukeProc, avolid, &forceSal, 0, wpath);
161     unlink("/tmp/vNukeXX");     /* clean it up now */
162 #endif
163     if (code == 0) {
164         /* actually do the idecs now */
165         for(ti=allInodes; ti; ti=ti->next) {
166             for(i=0;i<ti->freePtr;i++) {
167 #ifndef AFS_PTHREAD_ENV
168                 IOMGR_Poll();   /* keep RPC running */
169 #endif /* !AFS_PTHREAD_ENV */
170                 /* idec this inode into oblivion */
171 #ifdef AFS_NAMEI_ENV
172 #ifdef AFS_NT40_ENV
173                 IH_INIT(fileH, (int) (*lastDevComp - 'A'), avolid,
174                         ti->inode[i]);
175                 nt_HandleToName(path, fileH);
176 #else
177                 IH_INIT(fileH, (int) volutil_GetPartitionID(aname), avolid,
178                         ti->inode[i]);
179                 namei_HandleToName(&ufs_name, fileH);
180                 path = ufs_name.n_path;
181 #endif /* AFS_NT40_ENV */
182                 IH_RELEASE(fileH);
183                 if (unlink(path)<0) {
184                     Log("Nuke: Failed to remove %s\n", path);
185                 }
186 #else /* AFS_NAMEI_ENV */
187                 IH_INIT(fileH, (int) tstat.st_dev, avolid,
188                         ti->inode[i]);
189                 for(j=0;j<ti->count[i];j++) {
190                     code = IH_DEC(fileH, ti->inode[i], avolid);
191                 }
192                 IH_RELEASE(fileH);
193 #endif /* AFS_NAMEI_ENV */
194             }
195             ni = ti->next;
196             free(ti);
197         }
198         code = 0;       /* we really don't care about it except for debugging */
199         allInodes = NULL;
200
201         /* at this point, we should try to remove the volume header file itself.
202          * the volume header file is the file named VNNNNN.vol in the UFS file
203          * system, and is a normal file.  As such, it is not stamped with the
204          * volume's ID in its inode, and has to be removed explicitly.
205          */
206         /* reuse devName buffer now */
207 #ifdef AFS_NT40_ENV
208         afs_snprintf(devName, sizeof devName,
209                      "%c:\\%s", *lastDevComp , VolumeExternalName(avolid));
210 #else
211         afs_snprintf(devName, sizeof devName,
212                      "%s/%s", aname, VolumeExternalName(avolid));
213 #endif /* AFS_NT40_ENV */
214         code = unlink(devName);
215         if (code) code = errno;
216     }
217     else {
218         /* just free things */
219         for(ti=allInodes; ti; ti = ni) {
220             ni = ti->next;
221             free(ti);
222         }
223         allInodes = NULL;
224     }
225     ReleaseWriteLock(&localLock);
226     return code;
227 }
228