Import Upstream version 1.8.5
[hcoop/debian/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 #include <roken.h>
14
15 #include <afs/opr.h>
16 #include <afs/afsint.h>
17 #include <rx/rx_queue.h>
18
19 #include <afs/afsutil.h>
20
21 #include "nfs.h"
22 #include "lwp.h"
23 #include "lock.h"
24 #include <afs/afssyscalls.h>
25 #include "ihandle.h"
26 #include "vnode.h"
27 #include "volume.h"
28 #include "partition.h"
29 #include "viceinode.h"
30 #include "salvage.h"
31 #include "daemon_com.h"
32 #include "fssync.h"
33 #include "common.h"
34
35 struct Lock localLock;
36
37 #define MAXATONCE 100
38 /* structure containing neatly packed set of inodes and the # of times we'll have
39 * to idec them in order to reclaim their storage. NukeProc, called by ListViceInodes,
40 * builds this list for us.
41 */
42 struct ilist {
43 struct ilist *next;
44 afs_int32 freePtr; /* first free index in this table */
45 Inode inode[MAXATONCE]; /* inode # */
46 afs_int32 count[MAXATONCE]; /* link count */
47 };
48
49 /* called with a structure specifying info about the inode, and our rock (which
50 * is the volume ID. Returns true if we should keep this inode, otherwise false.
51 */
52 static int
53 NukeProc(struct ViceInodeInfo *ainfo, VolumeId avolid, void *arock)
54 {
55 struct ilist **allInodes = (struct ilist **)arock;
56 struct ilist *ti;
57 afs_int32 i;
58
59 #ifndef AFS_PTHREAD_ENV
60 IOMGR_Poll(); /* poll so we don't kill the RPC connection */
61 #endif /* !AFS_PTHREAD_ENV */
62
63 /* check if this is the volume we're looking for */
64 if (ainfo->u.vnode.vnodeNumber == INODESPECIAL) {
65 /* For special inodes, look at both the volume id and the parent id.
66 * If we were given an RW vol id to nuke, we should delete the special
67 * inodes for all volumes in the VG, since we're deleting all of the
68 * regular inodes, too. If we don't do this, on namei would be
69 * impossible to nuke the special inodes for a non-RW volume. */
70 if (ainfo->u.special.volumeId != avolid && ainfo->u.special.parentId != avolid) {
71 return 0;
72 }
73 } else {
74 if (ainfo->u.vnode.volumeId != avolid) {
75 return 0; /* don't want this one */
76 }
77 }
78
79 /* record the info */
80 if (!*allInodes || (*allInodes)->freePtr >= MAXATONCE) {
81 ti = calloc(1, sizeof(struct ilist));
82 ti->next = *allInodes;
83 *allInodes = ti;
84 } else
85 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
103 nuke(char *aname, VolumeId avolid)
104 {
105 /* first process the partition containing this junk */
106 struct afs_stat_st tstat;
107 struct ilist *ti, *ni, *li=NULL;
108 afs_int32 code;
109 int i, forceSal;
110 char wpath[100];
111 char *lastDevComp;
112 struct DiskPartition64 *dp;
113 #ifdef AFS_NAMEI_ENV
114 char *path;
115
116 namei_t ufs_name;
117 #endif /* AFS_NAMEI_ENV */
118 #ifndef AFS_NAMEI_ENV
119 char devName[64];
120 #endif /* !AFS_NAMEI_ENV */
121 IHandle_t *fileH;
122 struct ilist *allInodes = 0;
123
124 if (avolid == 0)
125 return EINVAL;
126 code = afs_stat(aname, &tstat);
127 if (code || (dp = VGetPartition(aname, 0)) == NULL) {
128 printf("volnuke: partition %s does not exist.\n", aname);
129 if (!code) {
130 code = EINVAL;
131 }
132 return code;
133 }
134 /* get the device name for the partition */
135 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
136 lastDevComp = aname;
137 #else
138 #ifdef AFS_NT40_ENV
139 lastDevComp = &aname[strlen(aname) - 1];
140 *lastDevComp = toupper(*lastDevComp);
141 #else
142 {
143 char *tfile = vol_DevName(tstat.st_dev, wpath);
144 if (!tfile) {
145 printf("volnuke: can't find %s's device.\n", aname);
146 return 1;
147 }
148 strcpy(devName, tfile); /* save this from the static buffer */
149 }
150 /* aim lastDevComp at the 'foo' of '/dev/foo' */
151 lastDevComp = strrchr(devName, OS_DIRSEPC);
152 /* either points at slash, or there is no slash; adjust appropriately */
153 if (lastDevComp)
154 lastDevComp++;
155 else
156 lastDevComp = devName;
157 #endif /* AFS_NT40_ENV */
158 #endif /* AFS_NAMEI_ENV && !AFS_NT40_ENV */
159
160 ObtainWriteLock(&localLock);
161 /* OK, we have the mounted on place, aname, the device name (in devName).
162 * all we need to do to call ListViceInodes is find the inodes for the
163 * volume we're nuking.
164 */
165 code =
166 ListViceInodes(lastDevComp, aname, INVALID_FD, NukeProc, avolid, &forceSal,
167 0, wpath, &allInodes);
168 if (code == 0) {
169 /* actually do the idecs now */
170 for (ti = allInodes; ti; ti = ti->next) {
171 for (i = 0; i < ti->freePtr; i++) {
172 #ifndef AFS_PTHREAD_ENV
173 IOMGR_Poll(); /* keep RPC running */
174 #endif /* !AFS_PTHREAD_ENV */
175 /* idec this inode into oblivion */
176 #ifdef AFS_NAMEI_ENV
177 #ifdef AFS_NT40_ENV
178 IH_INIT(fileH, (int)(*lastDevComp - 'A'), avolid,
179 ti->inode[i]);
180 #else
181 IH_INIT(fileH, (int)volutil_GetPartitionID(aname), avolid,
182 ti->inode[i]);
183 #endif /* AFS_NT40_ENV */
184 namei_HandleToName(&ufs_name, fileH);
185 path = ufs_name.n_path;
186 IH_RELEASE(fileH);
187 if (OS_UNLINK(path) < 0) {
188 Log("Nuke: Failed to remove %s\n", path);
189 }
190 #else /* AFS_NAMEI_ENV */
191 IH_INIT(fileH, (int)tstat.st_dev, avolid, ti->inode[i]);
192 {
193 int j;
194 for (j = 0; j < ti->count[i]; j++) {
195 code = IH_DEC(fileH, ti->inode[i], avolid);
196 }
197 }
198 IH_RELEASE(fileH);
199 #endif /* AFS_NAMEI_ENV */
200 }
201 if (li) free(li);
202 li = ti;
203 }
204 if (li) free(li);
205
206 allInodes = NULL;
207
208 /* at this point, we should try to remove the volume header file itself.
209 * the volume header file is the file named VNNNNN.vol in the UFS file
210 * system, and is a normal file. As such, it is not stamped with the
211 * volume's ID in its inode, and has to be removed explicitly.
212 */
213 code = VDestroyVolumeDiskHeader(dp, avolid, 0);
214 } else {
215 /* just free things */
216 for (ti = allInodes; ti; ti = ni) {
217 ni = ti->next;
218 if (li) free(li);
219 li = ti;
220 }
221 if (li) free(li);
222 allInodes = NULL;
223 }
224 ReleaseWriteLock(&localLock);
225 return code;
226 }