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