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