down with assert, up with osi_Assert
[openafs.git] / src / volser / voltrans.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  *  Module:         Voltrans.c
12  *  System:         Volser
13  *  Instituition:           ITC, CMU
14  *  Date:                   December, 88
15  */
16
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20
21 #ifdef AFS_NT40_ENV
22 #include <afs/afsutil.h>
23 #else
24 #include <sys/time.h>
25 #endif
26
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <errno.h>
30 #include <string.h>
31 #ifdef AFS_NT40_ENV
32 #include <fcntl.h>
33 #include <winsock2.h>
34 #else
35 #include <sys/file.h>
36 #include <netinet/in.h>
37 #include <unistd.h>
38 #endif
39 #include <dirent.h>
40 #include <sys/stat.h>
41 #include <afs/afsint.h>
42 #include <signal.h>
43 #include <afs/afs_assert.h>
44 #include <afs/prs_fs.h>
45 #include <afs/nfs.h>
46 #include <lwp.h>
47 #include <lock.h>
48 #include <afs/cellconfig.h>
49 #include <afs/keys.h>
50 #include <rx/rx.h>
51 #include <ubik.h>
52 #include <afs/ihandle.h>
53 #ifdef AFS_NT40_ENV
54 #include <afs/ntops.h>
55 #endif
56 #include <afs/vnode.h>
57 #include <afs/volume.h>
58
59 #include "volint.h"
60 #include "volser.h"
61 #include "volser_internal.h"
62
63 static struct volser_trans *allTrans = 0;
64 static afs_int32 transCounter = 1;
65
66 /* create a new transaction, returning ptr to same with high ref count */
67 struct volser_trans *
68 NewTrans(afs_uint32 avol, afs_int32 apart)
69 {
70     /* set volid, next, partition */
71     struct volser_trans *tt, *newtt;
72     struct timeval tp;
73     struct timezone tzp;
74
75     newtt = (struct volser_trans *)malloc(sizeof(struct volser_trans));
76     VTRANS_LOCK;
77     /* don't allow the same volume to be attached twice */
78     for (tt = allTrans; tt; tt = tt->next) {
79         if ((tt->volid == avol) && (tt->partition == apart)) {
80             VTRANS_UNLOCK;
81             free(newtt);
82             return (struct volser_trans *)0;    /* volume busy */
83         }
84     }
85     tt = newtt;
86     memset(tt, 0, sizeof(struct volser_trans));
87     tt->volid = avol;
88     tt->partition = apart;
89     tt->refCount = 1;
90     tt->rxCallPtr = (struct rx_call *)0;
91     strcpy(tt->lastProcName, "");
92     gettimeofday(&tp, &tzp);
93     tt->creationTime = tp.tv_sec;
94     tt->time = FT_ApproxTime();
95     tt->tid = transCounter++;
96     tt->next = allTrans;
97     VTRANS_OBJ_LOCK_INIT(tt);
98     allTrans = tt;
99     VTRANS_UNLOCK;
100     return tt;
101 }
102
103 /* find a trans, again returning with high ref count */
104 struct volser_trans *
105 FindTrans(afs_int32 atrans)
106 {
107     struct volser_trans *tt;
108     VTRANS_LOCK;
109     for (tt = allTrans; tt; tt = tt->next) {
110         if (tt->tid == atrans) {
111             tt->time = FT_ApproxTime();
112             tt->refCount++;
113             VTRANS_UNLOCK;
114             return tt;
115         }
116     }
117     VTRANS_UNLOCK;
118     return (struct volser_trans *)0;
119 }
120
121 /* delete transaction if refcount == 1, otherwise queue delete for later.  Does implicit TRELE */
122 afs_int32
123 DeleteTrans(struct volser_trans *atrans, afs_int32 lock)
124 {
125     struct volser_trans *tt, **lt;
126     Error error;
127
128     if (lock) VTRANS_LOCK;
129     if (atrans->refCount > 1) {
130         /* someone else is using it now */
131         atrans->refCount--;
132         atrans->tflags |= TTDeleted;
133         if (lock) VTRANS_UNLOCK;
134         return 0;
135     }
136
137     /* otherwise we zap it ourselves */
138     lt = &allTrans;
139     for (tt = *lt; tt; lt = &tt->next, tt = *lt) {
140         if (tt == atrans) {
141             if (tt->volume)
142                 VDetachVolume(&error, tt->volume);
143             tt->volume = NULL;
144             if (tt->rxCallPtr)
145                 rxi_CallError(tt->rxCallPtr, RX_CALL_DEAD);
146             *lt = tt->next;
147             VTRANS_OBJ_LOCK_DESTROY(tt);
148             free(tt);
149             if (lock) VTRANS_UNLOCK;
150             return 0;
151         }
152     }
153     if (lock) VTRANS_UNLOCK;
154     return -1;                  /* failed to find the transaction in the generic list */
155 }
156
157 /* THOLD is a macro defined in volser.h */
158
159 /* put a transaction back */
160 afs_int32
161 TRELE(struct volser_trans *at)
162 {
163     VTRANS_LOCK;
164     if (at->refCount == 0) {
165         Log("TRELE: bad refcount\n");
166         VTRANS_UNLOCK;
167         return VOLSERTRELE_ERROR;
168     }
169
170     at->time = FT_ApproxTime(); /* we're still using it */
171     if (at->refCount == 1 && (at->tflags & TTDeleted)) {
172         DeleteTrans(at, 0);
173         VTRANS_UNLOCK;
174         return 0;
175     }
176     /* otherwise simply drop refcount */
177     at->refCount--;
178     VTRANS_UNLOCK;
179     return 0;
180 }
181
182 /* look for old transactions and delete them */
183 #define OLDTRANSTIME        600 /* seconds */
184 #define OLDTRANSWARN        300 /* seconds */
185 static int GCDeletes = 0;
186 afs_int32
187 GCTrans(void)
188 {
189     struct volser_trans *tt, *nt;
190     afs_int32 now;
191
192     now = FT_ApproxTime();
193
194     VTRANS_LOCK;
195     for (tt = allTrans; tt; tt = nt) {
196         nt = tt->next;          /* remember in case we zap it */
197         if (tt->time + OLDTRANSWARN < now) {
198             Log("trans %u on volume %u %s than %d seconds\n", tt->tid,
199                 tt->volid,
200                 ((tt->refCount > 0) ? "is older" : "has been idle for more"),
201                 (((now - tt->time) / GCWAKEUP) * GCWAKEUP));
202         }
203         if (tt->refCount > 0)
204             continue;
205         if (tt->time + OLDTRANSTIME < now) {
206             Log("trans %u on volume %u has timed out\n", tt->tid, tt->volid);
207
208             tt->refCount++;     /* we're using it now */
209
210             if (tt->volume && V_destroyMe(tt->volume) == DESTROY_ME
211                 && !(tt->vflags & VTDeleted)) {
212
213                 Error error;
214
215                 Log("Deleting timed-out temporary volume %lu\n",
216                     (long unsigned) tt->volid);
217
218                 VTRANS_OBJ_LOCK(tt);
219                 tt->vflags |= VTDeleted;
220                 VTRANS_OBJ_UNLOCK(tt);
221
222                 VTRANS_UNLOCK;
223                 VPurgeVolume(&error, tt->volume);
224                 VTRANS_LOCK;
225             }
226
227             DeleteTrans(tt, 0); /* drops refCount or deletes it */
228             GCDeletes++;
229         }
230     }
231     VTRANS_UNLOCK;
232     return 0;
233 }
234
235 /*return the head of the transaction list */
236 struct volser_trans *
237 TransList(void)
238 {
239     return (allTrans);
240 }