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