110536790df6312f381d8dc5d9925198ee1a41da
[openafs.git] / src / vol / purge.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 /*
11         System:         VICE-TWO
12         Module:         purge.c
13         Institution:    The Information Technology Center, Carnegie-Mellon University
14
15  */
16 #include <afsconfig.h>
17 #include <afs/param.h>
18
19 RCSID("$Header$");
20
21 #include <stdio.h>
22 #ifdef AFS_NT40_ENV
23 #include <fcntl.h>
24 #include <io.h>
25 #else
26 #include <sys/param.h>
27 #include <sys/file.h>
28 #include <sys/time.h>
29 #endif
30 #ifdef HAVE_STRING_H
31 #include <string.h>
32 #else
33 #ifdef HAVE_STRINGS_H
34 #include <strings.h>
35 #endif
36 #endif
37 #include <sys/stat.h>
38 #include <afs/assert.h>
39
40 #include <rx/xdr.h>
41 #include "afs/afsint.h"
42 #include "nfs.h"
43 #include "lwp.h"
44 #include "lock.h"
45 #include <afs/afssyscalls.h>
46 #include "ihandle.h"
47 #ifdef AFS_NT40_ENV
48 #include "ntops.h"
49 #endif
50 #include "vnode.h"
51 #include "volume.h"
52 #include "viceinode.h"
53 #include "partition.h"
54 #include "fssync.h"
55
56 /* forward declarations */
57 void  PurgeIndex_r(Volume *vp, VnodeClass class);
58 void PurgeHeader_r(Volume *vp);
59
60 void VPurgeVolume_r(Error *ec, Volume *vp)
61 {
62     struct DiskPartition *tpartp = vp->partition;    
63     char purgePath[MAXPATHLEN];
64
65     /* N.B.  it's important here to use the partition pointed to by the
66      * volume header. This routine can, under some circumstances, be called
67      * when two volumes with the same id exist on different partitions.
68      */
69     sprintf(purgePath, "%s/%s", VPartitionPath(vp->partition),
70             VolumeExternalName(V_id(vp)));
71     PurgeIndex_r(vp, vLarge);
72     PurgeIndex_r(vp, vSmall);
73     PurgeHeader_r(vp);
74     unlink(purgePath);
75     /*
76      * Call the fileserver to break all call backs for that volume
77      */
78         FSYNC_askfs(V_id(vp), tpartp->name, FSYNC_RESTOREVOLUME, 0);
79 }
80
81 void VPurgeVolume(Error *ec, Volume *vp)
82 {
83     VOL_LOCK
84     VPurgeVolume_r(ec, vp);
85     VOL_UNLOCK
86 }
87
88 #define MAXOBLITATONCE  200
89 /* delete a portion of an index, adjusting offset appropriately.  Returns 0 if
90    things work and we should be called again, 1 if success full and done, and -1
91    if an error occurred.  It adjusts offset appropriately on 0 or 1 return codes,
92    and otherwise doesn't touch it */
93 static ObliterateRegion(avp, aclass, afile, aoffset)
94 afs_int32 *aoffset;
95 StreamHandle_t *afile;
96 VnodeClass aclass;
97 Volume *avp; {
98     register struct VnodeClassInfo *vcp;
99     Inode inodes[MAXOBLITATONCE];
100     register afs_int32 iindex, nscanned;
101     afs_int32 offset;
102     char buf[SIZEOF_LARGEDISKVNODE];
103     int hitEOF;
104     register int i;
105     register afs_int32 code;
106     register struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
107
108     hitEOF = 0;
109     vcp = &VnodeClassInfo[aclass];
110     offset = *aoffset;  /* original offset */
111     iindex = 0;
112     nscanned = 0;
113     /* advance over up to MAXOBLITATONCE inodes.  nscanned tells us how many we examined.
114        We remember the inodes in an array, and idec them after zeroing them in the index.
115        The reason for these contortions is to make volume deletion idempotent, even
116        if we crash in the middle of a delete operation. */
117     STREAM_SEEK(afile, offset, 0);
118     while (1) {
119         if (iindex >= MAXOBLITATONCE) {
120             break;
121         }
122         code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
123         nscanned++;
124         offset += vcp->diskSize;
125         if (code != 1) {
126             hitEOF = 1;
127             break;
128         }
129         if (vnode->type != vNull) {
130             if (vnode->vnodeMagic != vcp->magic)
131                 goto fail; /* something really wrong; let salvager take care of it */
132             if (VNDISK_GET_INO(vnode))
133                 inodes[iindex++] = VNDISK_GET_INO(vnode);
134         }
135     }
136
137     /* next, obliterate the index and fflush (and fsync) it */
138     STREAM_SEEK(afile, *aoffset, 0);    /* seek back to start of vnode index region */
139     memset(buf, 0, sizeof(buf));        /* zero out our proto-vnode */
140     for(i=0;i<nscanned;i++) {
141         if (STREAM_WRITE(buf, vcp->diskSize, 1, afile) != 1)
142             goto fail;
143     }
144     STREAM_FLUSH(afile);                /* ensure 0s are on the disk */
145     OS_SYNC(afile->str_fd);
146
147     /* finally, do the idec's */
148     for(i=0;i<iindex;i++) {
149         IH_DEC(V_linkHandle(avp), inodes[i], V_parentId(avp));
150         DOPOLL;
151     }
152
153     /* return the new offset */
154     *aoffset = offset;
155     return hitEOF;      /* return 1 if hit EOF (don't call again), otherwise 0 */
156
157   fail:
158     return -1;
159 }
160
161 void PurgeIndex(Volume *vp, VnodeClass class)
162 {
163     VOL_LOCK
164     PurgeIndex_r(vp, class);
165     VOL_UNLOCK
166 }
167
168 void  PurgeIndex_r(Volume *vp, VnodeClass class)
169 {
170     StreamHandle_t *ifile;
171     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
172     afs_int32 offset;
173     register afs_int32 code;
174     FdHandle_t *fdP;
175     
176
177     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
178     if (fdP == NULL)
179         return;
180
181     ifile = FDH_FDOPEN(fdP, "r+");
182     if (!ifile) {
183         FDH_REALLYCLOSE(fdP);
184         return;
185     }
186
187     offset = vcp->diskSize;
188     while(1) {
189         code = ObliterateRegion(vp, class, ifile, &offset);
190         if (code) break;        /* if error or hit EOF */
191     }
192     STREAM_CLOSE(ifile);
193     FDH_CLOSE(fdP);
194 }
195
196 void PurgeHeader(Volume *vp)
197 {
198     VOL_LOCK
199     PurgeHeader_r(vp);
200     VOL_UNLOCK
201 }
202
203 void PurgeHeader_r(Volume *vp)
204 {
205     IH_REALLYCLOSE(V_diskDataHandle(vp));
206     IH_DEC(V_linkHandle(vp), vp->vnodeIndex[vLarge].handle->ih_ino, V_id(vp));
207     IH_DEC(V_linkHandle(vp), vp->vnodeIndex[vSmall].handle->ih_ino, V_id(vp));
208     IH_DEC(V_linkHandle(vp), vp->diskDataHandle->ih_ino, V_id(vp));
209 #ifdef AFS_NAMEI_ENV
210     /* And last, but not least, the link count table itself. */
211     IH_REALLYCLOSE(V_linkHandle(vp));
212     IH_DEC(V_linkHandle(vp), vp->linkHandle->ih_ino, V_parentId(vp));
213 #endif
214 }
215
216