libafscp: Actually return callback from FindCallback
[openafs.git] / src / libafscp / afscp_fid.c
1 /* AUTORIGHTS
2 Copyright (C) 2003 - 2010 Chaskiel Grundman
3 All rights reserved
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <afsconfig.h>
28 #include <afs/param.h>
29
30 #include <roken.h>
31
32 #include <search.h>
33
34 #include <afs/vlserver.h>
35 #include <afs/vldbint.h>
36 #include "afscp.h"
37 #include "afscp_internal.h"
38
39 /*
40  * Allocate and populate an afscp_venusfid struct from component parts
41  */
42 struct afscp_venusfid *
43 afscp_MakeFid(struct afscp_cell *cell, afs_uint32 volume,
44               afs_uint32 vnode, afs_uint32 unique)
45 {
46     struct afscp_venusfid *ret;
47
48     if (cell == NULL) {
49         return NULL;
50     }
51     ret = malloc(sizeof(struct afscp_venusfid));
52     if (ret == NULL) {
53         afscp_errno = errno;
54         return NULL;
55     }
56     ret->cell = cell;
57     ret->fid.Volume = volume;
58     ret->fid.Vnode = vnode;
59     ret->fid.Unique = unique;
60     return ret;
61 }
62
63 /*
64  * Duplicate an existing afscp_venusfid struct
65  */
66 struct afscp_venusfid *
67 afscp_DupFid(const struct afscp_venusfid *in)
68 {
69     struct afscp_venusfid *ret;
70
71     ret = malloc(sizeof(struct afscp_venusfid));
72     if (ret == NULL) {
73         afscp_errno = errno;
74         return NULL;
75     }
76     ret->cell = in->cell;
77     ret->fid.Volume = in->fid.Volume;
78     ret->fid.Vnode = in->fid.Vnode;
79     ret->fid.Unique = in->fid.Unique;
80     return ret;
81 }
82
83 void
84 afscp_FreeFid(struct afscp_venusfid *avfp)
85 {
86     if (avfp != NULL)
87         free(avfp);
88 }
89
90 static int
91 statcompare(const void *a, const void *b)
92 {
93     const struct afscp_statent *sa = a, *sb = b;
94     if (sa->me.fid.Vnode < sb->me.fid.Vnode)
95         return -1;
96     if (sa->me.fid.Vnode > sb->me.fid.Vnode)
97         return 1;
98     if (sa->me.fid.Unique < sb->me.fid.Unique)
99         return -1;
100     if (sa->me.fid.Unique > sb->me.fid.Unique)
101         return 1;
102     return 0;
103 }
104
105 static void
106 _StatCleanup(struct afscp_statent *stored)
107 {
108     pthread_cond_destroy(&(stored->cv));
109     pthread_mutex_unlock(&(stored->mtx));
110     pthread_mutex_destroy(&(stored->mtx));
111     free(stored);
112 }
113
114 int
115 afscp_WaitForCallback(const struct afscp_venusfid *fid, int seconds)
116 {
117     void **cached;
118     struct afscp_volume *v;
119     struct afscp_statent *stored, key;
120     int code = 0;
121
122     v = afscp_VolumeById(fid->cell, fid->fid.Volume);
123     if (v == NULL) {
124         return -1;
125     }
126     memmove(&key.me, fid, sizeof(*fid));
127
128     cached = tfind(&key, &v->statcache, statcompare);
129     if (cached != NULL) {
130         struct timeval tv;
131         struct timespec ts;
132
133         stored = *(struct afscp_statent **)cached;
134
135         if (seconds) {
136             gettimeofday(&tv, NULL);
137             ts.tv_sec = tv.tv_sec + seconds;
138             ts.tv_nsec = 0;
139         }
140
141         pthread_mutex_lock(&(stored->mtx));
142         stored->nwaiters++;
143         if (seconds)
144             code = pthread_cond_timedwait(&(stored->cv), &(stored->mtx), &ts);
145         else
146             pthread_cond_wait(&(stored->cv), &(stored->mtx));
147         if ((stored->nwaiters == 1) && stored->cleanup)
148             _StatCleanup(stored);
149         else
150             stored->nwaiters--;
151         pthread_mutex_unlock(&(stored->mtx));
152     }
153     if ((code == EINTR) || (code == ETIMEDOUT)) {
154         afscp_errno = code;
155         code = -1;
156     }      
157     return code;
158 }
159
160 int
161 afscp_GetStatus(const struct afscp_venusfid *fid, struct AFSFetchStatus *s)
162 {
163     struct afscp_volume *v;
164     struct afscp_server *server;
165     struct AFSCallBack cb;
166     struct AFSVolSync vs;
167     struct AFSFid tf = fid->fid;
168     struct afscp_statent *stored, key;
169     void *cached;
170     int code, i, j;
171     time_t now;
172
173     v = afscp_VolumeById(fid->cell, fid->fid.Volume);
174     if (v == NULL) {
175         return -1;
176     }
177     memset(&key, 0, sizeof(key));
178     memcpy(&key.me, fid, sizeof(*fid));
179
180     cached = tfind(&key, &v->statcache, statcompare);
181     if (cached != NULL) {
182         stored = *(struct afscp_statent **)cached;
183         pthread_mutex_lock(&(stored->mtx));
184         memmove(s, &stored->status, sizeof(*s));
185         afs_dprintf(("Stat %u.%lu.%lu.%lu returning cached result\n",
186                      fid->cell->id, fid->fid.Volume, fid->fid.Vnode,
187                      fid->fid.Unique));
188         if (stored->nwaiters)
189             pthread_cond_broadcast(&(stored->cv));
190         pthread_mutex_unlock(&(stored->mtx));
191         return 0;
192     }
193
194     code = ENOENT;
195     for (i = 0; i < v->nservers; i++) {
196         server = afscp_ServerByIndex(v->servers[i]);
197         if (server && server->naddrs > 0) {
198             for (j = 0; j < server->naddrs; j++) {
199                 time(&now);
200                 code = RXAFS_FetchStatus(server->conns[j], &tf, s, &cb, &vs);
201                 if (code == 0) {
202                     afscp_AddCallBack(server, &fid->fid, s, &cb, now);  /* calls _StatStuff */
203                     afs_dprintf(("Stat %d.%lu.%lu.%lu"
204                                  " ok: type %ld size %ld\n",
205                                  fid->cell->id,
206                                  afs_printable_uint32_lu(fid->fid.Volume),
207                                  afs_printable_uint32_lu(fid->fid.Vnode),
208                                  afs_printable_uint32_lu(fid->fid.Unique),
209                                  afs_printable_int32_ld(s->FileType),
210                                  afs_printable_int32_ld(s->Length)));
211                     return 0;
212                 }
213             }
214         }
215     }
216     afscp_errno = code;
217     return -1;
218 }
219
220 int
221 afscp_Stat(const struct afscp_venusfid *fid, struct stat *s)
222 {
223
224     struct AFSFetchStatus status;
225     int code;
226
227
228     if (s == NULL || fid == NULL) {
229         fprintf(stderr, "NULL args given to afscp_Stat, cannot continue\n");
230         return -1;
231     }
232
233     code = afscp_GetStatus(fid, &status);
234     if (code != 0) {
235         return code;
236     }
237
238     if (status.FileType == File)
239         s->st_mode = S_IFREG;
240     else if (status.FileType == Directory)
241         s->st_mode = S_IFDIR;
242 #ifndef AFS_NT40_ENV
243     else if (status.FileType == SymbolicLink)
244         s->st_mode = S_IFLNK;
245     /* a behavior needs to be defined on Windows */
246 #endif
247     else {
248         afscp_errno = EINVAL;
249         return -1;
250     }
251     s->st_mode |= (status.UnixModeBits & (~S_IFMT));
252     s->st_nlink = status.LinkCount;
253     s->st_size = status.Length;
254     s->st_uid = status.Owner;
255     /*s->st_blksize=status.SegSize; */
256     s->st_atime = s->st_mtime = status.ClientModTime;
257     s->st_ctime = status.ServerModTime;
258     s->st_gid = status.Group;
259     return 0;
260 }
261
262 int
263 afscp_CheckCallBack(const struct afscp_venusfid *fid, const struct afscp_server *server, afs_uint32 *expiretime)
264 {
265     struct AFSFetchStatus status;
266     struct afscp_callback *cb = NULL;
267     int code;
268     time_t now;
269
270     if (expiretime == NULL || fid == NULL) {
271         fprintf(stderr, "NULL args given to afscp_CheckCallback, cannot continue\n");
272         return -1;
273     }
274
275     *expiretime = 0;
276
277     code = afscp_GetStatus(fid, &status);
278     if (code != 0)
279         return code;
280
281     code = afscp_FindCallBack(fid, server, &cb);
282     if (code != 0)
283         return code;
284
285     if (cb) {
286         time(&now);
287         *expiretime = cb->cb.ExpirationTime + cb->as_of - now;
288     }
289
290     return 0;
291 }
292
293 int
294 _StatInvalidate(const struct afscp_venusfid *fid)
295 {
296     struct afscp_volume *v;
297     struct afscp_statent *stored, key;
298     void **cached;
299
300     v = afscp_VolumeById(fid->cell, fid->fid.Volume);
301     if (v == NULL) {
302         return -1;
303     }
304     memmove(&key.me, fid, sizeof(*fid));
305
306     cached = tfind(&key, &v->statcache, statcompare);
307     if (cached != NULL) {
308         stored = *(struct afscp_statent **)cached;
309         pthread_mutex_lock(&(stored->mtx));
310         tdelete(&key, &v->statcache, statcompare);
311         if (stored->nwaiters) {
312             /* avoid blocking callback thread */
313             pthread_cond_broadcast(&(stored->cv));
314             stored->cleanup = 1;
315         } else
316             _StatCleanup(stored);
317         pthread_mutex_unlock(&(stored->mtx));
318     }
319     return 0;
320 }
321
322 int
323 _StatStuff(const struct afscp_venusfid *fid, const struct AFSFetchStatus *s)
324 {
325     struct afscp_volume *v;
326     struct afscp_statent key, *stored;
327     void **cached;
328
329     v = afscp_VolumeById(fid->cell, fid->fid.Volume);
330     if (v == NULL) {
331         return -1;
332     }
333     memmove(&key.me, fid, sizeof(*fid));
334
335     cached = tsearch(&key, &v->statcache, statcompare);
336     if (cached != NULL) {
337         stored = malloc(sizeof(struct afscp_statent));
338         if (stored != NULL) {
339             pthread_mutex_init(&(stored->mtx), NULL);
340             pthread_cond_init(&(stored->cv), NULL);
341             stored->nwaiters = 0;
342             stored->cleanup = 0;
343             memmove(&stored->me, fid, sizeof(*fid));
344             memmove(&stored->status, s, sizeof(*s));
345             *(struct afscp_statent **)cached = stored;
346         } else {
347             tdelete(&key, &v->statcache, statcompare);
348         }
349     }
350     return 0;
351 }
352
353 int
354 afscp_StoreStatus(const struct afscp_venusfid *fid, struct AFSStoreStatus *s)
355 {
356     struct afscp_volume *v;
357     struct afscp_server *server;
358     struct AFSVolSync vs;
359     struct AFSFetchStatus fst;
360     struct AFSFid tf = fid->fid;
361     int code, i, j;
362
363     v = afscp_VolumeById(fid->cell, fid->fid.Volume);
364     if (v == NULL) {
365         return -1;
366     }
367
368     code = ENOENT;
369     for (i = 0; i < v->nservers; i++) {
370         server = afscp_ServerByIndex(v->servers[i]);
371         if (server && server->naddrs > 0) {
372             for (j = 0; j < server->naddrs; j++) {
373                 code = RXAFS_StoreStatus(server->conns[j], &tf, s, &fst, &vs);
374                 if (code == 0) {
375                     _StatStuff(fid, &fst);      /* calls _StatStuff */
376                     return 0;
377                 }
378             }
379         }
380     }
381     afscp_errno = code;
382     return -1;
383 }