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