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