disconnected-rw-20080922
[openafs.git] / src / afs / afs_disconnected.c
1 /*
2  * This software has been released under the terms of the IBM Public
3  * License.  For details, see the LICENSE file in the top-level source
4  * directory or online at http://www.openafs.org/dl/license10.html
5  */
6
7 #include <afsconfig.h>
8 #include "afs/param.h"
9  
10 RCSID("$Header$");
11  
12 #include "afs/sysincludes.h"
13 #include "afsincludes.h"
14 #include "afs/afs_stats.h"      /* statistics */
15 #include "afs/lock.h"
16 #include "afs/afs_cbqueue.h"
17
18 #ifdef AFS_DISCON_ENV
19
20 #define dv_match(vc, fstat)                              \
21         ((vc->m.DataVersion.low == fstat.DataVersion) && \
22         (vc->m.DataVersion.high == fstat.dataVersionHigh))
23
24 /*! Global list of dirty vcaches. */
25 /*! Last added element. */
26 struct vcache *afs_DDirtyVCList = NULL;
27 /*! Head of list. */
28 struct vcache *afs_DDirtyVCListStart = NULL;
29 /*! Previous element in the list. */
30 struct vcache *afs_DDirtyVCListPrev = NULL;
31
32 /*! Locks list of dirty vcaches. */
33 afs_rwlock_t afs_DDirtyVCListLock;
34
35 extern afs_int32 *afs_dvhashTbl;        /*Data cache hash table */
36 extern afs_int32 *afs_dchashTbl;        /*Data cache hash table */
37 extern afs_int32 *afs_dvnextTbl;        /*Dcache hash table links */
38 extern afs_int32 *afs_dcnextTbl;        /*Dcache hash table links */
39 extern struct dcache **afs_indexTable;  /*Pointers to dcache entries */
40
41 /*! Vnode number. On file creation, use the current
42  *  value and increment it.
43  */
44 afs_uint32 afs_DisconVnode = 2;
45
46 /*! Conflict policy. */
47 enum {
48         CLIENT_WINS = 0,
49         SERVER_WINS,
50         LAST_CLOSER_WINS,
51         ASK
52 };
53
54 afs_int32 afs_ConflictPolicy = SERVER_WINS;
55
56 /*!
57  * Find the first dcache of a file that has the specified fid.
58  * Similar to afs_FindDCache, only that it takes a fid instead
59  * of a vcache and it can get the first dcache.
60  *
61  * \param afid
62  *
63  * \return The found dcache or NULL.
64  */
65 struct dcache *afs_FindDCacheByFid(register struct VenusFid *afid)
66 {
67     register afs_int32 i, index;
68     register struct dcache *tdc = NULL;
69
70     i = DVHash(afid);
71     ObtainWriteLock(&afs_xdcache, 758);
72     for (index = afs_dvhashTbl[i]; index != NULLIDX;) {
73         if (afs_indexUnique[index] == afid->Fid.Unique) {
74             tdc = afs_GetDSlot(index, NULL);
75             ReleaseReadLock(&tdc->tlock);
76             if (!FidCmp(&tdc->f.fid, afid)) {
77                 break;          /* leaving refCount high for caller */
78             }
79             afs_PutDCache(tdc);
80         }
81         index = afs_dvnextTbl[index];
82     }
83     ReleaseWriteLock(&afs_xdcache);
84
85     if (index == NULLIDX)
86         tdc = NULL;
87     return tdc;
88 }
89
90 /*!
91  * Generate a store status from a dirty vcache entry.
92  *
93  * \param avc Dirty vcache entry.
94  * \param astat
95  *
96  * \note The vnode must be share locked. It is called only on resync,
97  * where the vnode is write locked locally and and the server.
98  *
99  * \return Mask of operations.
100  */
101 int afs_GenStoreStatus(struct vcache *avc, struct AFSStoreStatus *astat)
102 {
103     if (!avc || !astat || !avc->ddirty_flags)
104         return 0;
105
106     /* Clean up store stat. */
107     memset(astat, 0, sizeof(struct AFSStoreStatus));
108
109     if (avc->ddirty_flags & VDisconSetTime) {
110         /* Update timestamp. */
111         astat->ClientModTime = avc->m.Date;
112         astat->Mask |= AFS_SETMODTIME;
113     }
114
115     if (avc->ddirty_flags & VDisconSetMode) {
116         /* Copy the mode bits. */
117         astat->UnixModeBits = avc->m.Mode;
118         astat->Mask |= AFS_SETMODE;
119    }
120
121    /* XXX: more to come... ?*/
122
123    return astat->Mask;
124 }
125
126 /*!
127  * Hook for filtering the local dir fid by searching the "." entry.
128  *
129  * \param hdata The fid to be filled.
130  */
131 int get_parent_dir_fid_hook(void *hdata,
132                                 char *aname,
133                                 afs_int32 vnode,
134                                 afs_int32 unique)
135 {
136     struct VenusFid *tfid = (struct VenusFid *) hdata;
137
138     if ((aname[0] == '.') && (aname[1] == '.') && !aname[2]) {
139         tfid->Fid.Vnode = vnode;
140         tfid->Fid.Unique = unique;
141         return 1;
142     }
143
144     return 0;
145 }
146
147 /*!
148  * Get a the dir's fid by looking in the vcache for simple files and
149  * in the ".." entry for directories.
150  *
151  * \param avc The file's vhash entry.
152  * \param afid Put the fid here.
153  */
154 int afs_GetParentDirFid(struct vcache *avc, struct VenusFid *afid)
155 {
156     struct dcache *tdc;
157
158     afid->Cell = avc->fid.Cell;
159     afid->Fid.Volume = avc->fid.Fid.Volume;
160
161     if (vType(avc) == VREG) {
162         /* Normal files have the dir fid embedded in the vcache. */
163         afid->Fid.Vnode = avc->parentVnode;
164         afid->Fid.Unique = avc->parentUnique;
165
166     } else if (vType(avc) == VDIR) {
167         /* If dir or parent dir created locally*/
168         tdc = afs_FindDCacheByFid(&avc->fid);
169         if (tdc) {
170             /* Lookup each entry for the fid. It should be the first. */
171             afs_dir_EnumerateDir(tdc, &get_parent_dir_fid_hook, afid);
172             afs_PutDCache(tdc);
173         }
174     }
175
176     return 0;
177 }
178
179 struct NameAndFid {
180     struct VenusFid *fid;
181     char *name;
182     int name_len;
183 };
184
185 /*!
186  * Hook that searches a certain fid's name.
187  *
188  * \param hdata NameAndFid structure containin a pointer to a fid
189  * and an allocate name. The name will be filled when hit.
190  */
191 int get_vnode_name_hook(void *hdata,
192                                 char *aname,
193                                 afs_int32 vnode,
194                                 afs_int32 unique)
195 {
196     struct NameAndFid *nf = (struct NameAndFid *) hdata;
197
198     if ((nf->fid->Fid.Vnode == vnode) &&
199         (nf->fid->Fid.Unique == unique)) {
200         nf->name_len = strlen(aname);
201         memcpy(nf->name, aname, nf->name_len);
202         nf->name[nf->name_len] = 0;
203
204         return 1;
205     }
206
207     return 0;
208 }
209
210 /*!
211  * Try to get a vnode's name by comparing all parent dir's entries
212  * to the given fid. It can also return the dir's dcache.
213  *
214  * \param avc The file's vcache.
215  * \param afid The parent dir's fid.
216  * \param aname A preallocated string for the name.
217  * \param deleted Has this file been deleted? If yes, use the shadow
218  * dir for looking up the name.
219  */
220 int afs_GetVnodeName(struct vcache *avc,
221                         struct VenusFid *afid,
222                         char *aname,
223                         int deleted)
224 {
225     int code = 0;
226     struct dcache *tdc;
227     struct vcache *parent_vc;
228     struct NameAndFid tnf;
229     struct VenusFid parent_fid;
230     struct VenusFid shadow_fid;
231
232     /* List dir contents and get it's tdc. */
233     if (deleted) {
234         /* For deleted files, get the shadow dir's tdc: */
235
236         /* Get the parent dir's vcache that contains the shadow fid. */
237         parent_fid.Cell = avc->fid.Cell;
238         parent_fid.Fid.Volume = avc->fid.Fid.Volume;
239         if (avc->ddirty_flags & VDisconRename) {
240             /* For renames the old dir fid is needed. */
241             parent_fid.Fid.Vnode = avc->oldVnode;
242             parent_fid.Fid.Unique = avc->oldUnique;
243         } else {
244             parent_fid.Fid.Vnode = afid->Fid.Vnode;
245             parent_fid.Fid.Unique = afid->Fid.Unique;
246         }
247
248         /* Get the parent dir's vcache that contains the shadow fid. */
249         ObtainSharedLock(&afs_xvcache, 755);
250         parent_vc = afs_FindVCache(&parent_fid, 0, 1);
251         ReleaseSharedLock(&afs_xvcache);
252         if (!parent_vc) {
253             return ENOENT;
254         }
255
256         shadow_fid.Cell = parent_vc->fid.Cell;
257         shadow_fid.Fid.Volume = parent_vc->fid.Fid.Volume;
258         shadow_fid.Fid.Vnode = parent_vc->shVnode;
259         shadow_fid.Fid.Unique = parent_vc->shUnique;
260
261         afs_PutVCache(parent_vc);
262
263         /* Get shadow dir's dcache. */
264         tdc = afs_FindDCacheByFid(&shadow_fid);
265
266     } else {
267
268         /* For normal files, look into the current dir's entry. */
269         tdc = afs_FindDCacheByFid(afid);
270     }                   /* if (deleted) */
271
272     if (tdc) {
273         tnf.fid = &avc->fid;
274         tnf.name_len = 0;
275         tnf.name = aname;
276         afs_dir_EnumerateDir(tdc, &get_vnode_name_hook, &tnf);
277         afs_PutDCache(tdc);
278     } else {
279         code = ENOENT;
280     }
281
282     return code;
283 }
284
285 struct DirtyChildrenCount {
286     struct vcache *vc;
287     afs_uint32 count;
288 };
289
290 /*!
291  * Lookup dirty deleted vnodes in this dir.
292  */
293 int chk_del_children_hook(void *hdata,
294                                 char *aname,
295                                 afs_int32 vnode,
296                                 afs_int32 unique)
297 {
298     struct VenusFid tfid;
299     struct DirtyChildrenCount *v = (struct DirtyChildrenCount *) hdata;
300     struct vcache *tvc;
301
302     if ((aname[0] == '.') && !aname[1])
303         /* Skip processing this dir again.
304          * It would result in an endless loop.
305          */
306         return 0;
307
308     if ((aname[0] == '.') && (aname[1] == '.') && !aname[2])
309         /* Don't process parent dir. */
310         return 0;
311
312     /* Get this file's vcache. */
313     tfid.Cell = v->vc->fid.Cell;
314     tfid.Fid.Volume = v->vc->fid.Fid.Volume;
315     tfid.Fid.Vnode = vnode;
316     tfid.Fid.Unique = unique;
317
318     ObtainSharedLock(&afs_xvcache, 757);
319     tvc = afs_FindVCache(&tfid, 0, 1);
320     ReleaseSharedLock(&afs_xvcache);
321
322     /* Count unfinished dirty children. VDisconShadowed can still be set,
323      * because we need it to remove the shadow dir.
324      */
325     if (tvc && tvc->ddirty_flags) {
326         v->count++;
327         afs_PutVCache(tvc);
328     }
329
330     return 0;
331 }
332
333 /*!
334  * Check if entries have been deleted in a vnode's shadow
335  * dir.
336  *
337  * \return Returns the number of dirty children.
338  *
339  * \note afs_DDirtyVCListLock must be write locked.
340  */
341 int afs_CheckDeletedChildren(struct vcache *avc)
342 {
343     struct dcache *tdc;
344     struct DirtyChildrenCount dcc;
345     struct VenusFid shadow_fid;
346
347     if (!(avc->ddirty_flags & VDisconShadowed))
348         /* Empty dir. */
349         return 0;
350
351     shadow_fid.Cell = avc->fid.Cell;
352     shadow_fid.Fid.Volume = avc->fid.Fid.Volume;
353     shadow_fid.Fid.Vnode = avc->shVnode;
354     shadow_fid.Fid.Unique = avc->shUnique;
355
356     dcc.count = 0;
357
358     /* Get shadow dir's dcache. */
359     tdc = afs_FindDCacheByFid(&shadow_fid);
360     if (tdc) {
361         dcc.vc = avc;
362         afs_dir_EnumerateDir(tdc, &chk_del_children_hook, &dcc);
363         afs_PutDCache(tdc);
364     }
365
366     return dcc.count;
367 }
368
369 /*!
370  * Changes a file's parent fid references.
371  */
372 int fix_children_fids_hook(void *hdata,
373                                 char *aname,
374                                 afs_int32 vnode,
375                                 afs_int32 unique)
376 {
377     struct VenusFid tfid;
378     struct VenusFid *afid = (struct VenusFid *) hdata;
379     struct vcache *tvc;
380     struct dcache *tdc = NULL;
381
382     if ((aname[0] == '.') && !aname[1])
383         return 0;
384
385     if ((aname[0] == '.') && (aname[1] == '.') && !aname[2])
386         return 0;
387
388     tfid.Cell = afid->Cell;
389     tfid.Fid.Volume = afid->Fid.Volume;
390     tfid.Fid.Vnode = vnode;
391     tfid.Fid.Unique = unique;
392
393     if (!(vnode % 2)) {
394         /* vnode's parity indicates that it's a file. */
395
396         /* Get the vcache. */
397         ObtainSharedLock(&afs_xvcache, 759);
398         tvc = afs_FindVCache(&tfid, 0, 1);
399         ReleaseSharedLock(&afs_xvcache);
400
401         /* Change the fields. */
402         if (tvc) {
403             tvc->parentVnode = afid->Fid.Vnode;
404             tvc->parentUnique = afid->Fid.Unique;
405
406             afs_PutVCache(tvc);
407         }
408     } else {
409         /* It's a dir. Fix this dir's .. entry to contain the new fid. */
410         /* Seek the dir's dcache. */
411         tdc = afs_FindDCacheByFid(&tfid);
412         if (tdc) {
413             /* Change the .. entry fid. */
414             afs_dir_ChangeFid(tdc, "..", NULL, &afid->Fid.Vnode);
415             afs_PutDCache(tdc);
416         }
417     }                   /* if (!(vnode % 2))*/
418
419     return 0;
420 }
421
422 /*!
423  * Fixes the parentVnode and parentUnique fields of all
424  * files (not dirs) contained in the directory pointed by
425  * old_fid. This is useful on resync, when a locally created dir
426  * get's a new fid and all the children references must be updated
427  * to reflect the new fid.
428  *
429  * \note The dir's fid hasn't been changed yet, it is still referenced
430  * with the old fid.
431  *
432  * \param old_fid The current dir's fid.
433  * \param new_fid The new dir's fid.
434  */
435 void afs_FixChildrenFids(struct VenusFid *old_fid, struct VenusFid *new_fid)
436 {
437     struct dcache *tdc;
438
439     /* Get shadow dir's dcache. */
440     tdc = afs_FindDCacheByFid(old_fid);
441     /* Change the fids. */
442     if (tdc) {
443         afs_dir_EnumerateDir(tdc, &fix_children_fids_hook, new_fid);
444         afs_PutDCache(tdc);
445     }
446 }
447
448 int list_dir_hook(void *hdata, char *aname, afs_int32 vnode, afs_int32 unique)
449 {
450     printf("list_dir_hook: %s v:%u u:%u\n", aname, vnode, unique);
451     return 0;
452 }
453
454 void afs_DbgListDirEntries(struct VenusFid *afid)
455 {
456     struct dcache *tdc;
457
458     /* Get shadow dir's dcache. */
459     tdc = afs_FindDCacheByFid(afid);
460     if (tdc) {
461         afs_dir_EnumerateDir(tdc, &list_dir_hook, NULL);
462         afs_PutDCache(tdc);
463     }
464 }
465
466 /*!
467  * Handles file renaming on reconnection:
468  * - Get the old name from the old dir's shadow dir.
469  * - Get the new name from the current dir.
470  * - Old dir fid and new dir fid are collected along the way.
471  * */
472 int afs_ProcessOpRename(struct vcache *avc, struct vrequest *areq)
473 {
474     struct VenusFid old_pdir_fid, new_pdir_fid;
475     char *old_name, *new_name;
476     struct AFSFetchStatus OutOldDirStatus, OutNewDirStatus;
477     struct AFSVolSync tsync;
478     struct conn *tc;
479     afs_uint32 code = 0;
480     XSTATS_DECLS;
481
482     /* Get old dir vcache. */
483     old_pdir_fid.Cell = avc->fid.Cell;
484     old_pdir_fid.Fid.Volume = avc->fid.Fid.Volume;
485     old_pdir_fid.Fid.Vnode = avc->oldVnode;
486     old_pdir_fid.Fid.Unique = avc->oldUnique;
487
488     /* Get old name. */
489     old_name = (char *) afs_osi_Alloc(AFSNAMEMAX);
490     if (!old_name) {
491         printf("afs_ProcessOpRename: Couldn't alloc space for old name.\n");
492         return ENOMEM;
493     }
494     code = afs_GetVnodeName(avc, &old_pdir_fid, old_name, 1);
495     if (code) {
496         printf("afs_ProcessOpRename: Couldn't find old name.\n");
497         code = ENOENT;
498         goto end2;
499     }
500
501     /* Alloc data first. */
502     new_name = (char *) afs_osi_Alloc(AFSNAMEMAX);
503     if (!new_name) {
504         printf("afs_ProcessOpRename: Couldn't alloc space for new name.\n");
505         code = ENOMEM;
506         goto end2;
507     }
508
509     if (avc->ddirty_flags & VDisconRenameSameDir) {
510         /* If we're in the same dir, don't do the lookups all over again,
511          * just copy fid and vcache from the old dir.
512          */
513         memcpy(&new_pdir_fid, &old_pdir_fid, sizeof(struct VenusFid));
514     } else {
515         /* Get parent dir's FID.*/
516         new_pdir_fid.Fid.Unique = 0;
517         afs_GetParentDirFid(avc, &new_pdir_fid);
518         if (!new_pdir_fid.Fid.Unique) {
519             printf("afs_ProcessOpRename: Couldn't find new parent dir FID.\n");
520             code = ENOENT;
521             goto end1;
522         }
523     }
524
525     /* And finally get the new name. */
526     code = afs_GetVnodeName(avc, &new_pdir_fid, new_name, 0);
527     if (code) {
528         printf("afs_ProcessOpRename: Couldn't find new name.\n");
529         code = ENOENT;
530         goto end1;
531     }
532
533     /* Send to data to server. */
534     do {
535         tc = afs_Conn(&old_pdir_fid, areq, SHARED_LOCK);
536         if (tc) {
537             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RENAME);
538             RX_AFS_GUNLOCK();
539             code = RXAFS_Rename(tc->id,
540                 (struct AFSFid *)&old_pdir_fid.Fid,
541                 old_name,
542                 (struct AFSFid *)&new_pdir_fid.Fid,
543                 new_name,
544                 &OutOldDirStatus,
545                 &OutNewDirStatus,
546                 &tsync);
547             RX_AFS_GLOCK();
548             XSTATS_END_TIME;
549         } else
550             code = -1;
551
552     } while (afs_Analyze(tc,
553                 code,
554                 &new_pdir_fid,
555                 areq,
556                 AFS_STATS_FS_RPCIDX_RENAME,
557                 SHARED_LOCK,
558                 NULL));
559
560     if (code)
561         printf("afs_ProcessOpRename: server code=%u\n", code);
562 end1:
563     afs_osi_Free(new_name, AFSNAMEMAX);
564 end2:
565     afs_osi_Free(old_name, AFSNAMEMAX);
566     return code;
567 }
568
569 /*!
570  * Handles all the reconnection details:
571  * - Get all the details about the vnode: name, fid, and parent dir fid.
572  * - Send data to server.
573  * - Handle errors.
574  * - Reorder vhash and dcaches in their hashes, using the newly acquired fid.
575  */
576 int afs_ProcessOpCreate(struct vcache *avc,
577                                 struct vrequest *areq,
578                                 struct AFS_UCRED *acred)
579 {
580     char *tname = NULL;
581     struct AFSStoreStatus InStatus;
582     struct AFSFetchStatus OutFidStatus, OutDirStatus;
583     struct VenusFid pdir_fid, newFid;
584     struct server *hostp = NULL;
585     struct AFSCallBack CallBack;
586     struct AFSVolSync tsync;
587     struct vcache *tdp = NULL, *tvc = NULL;
588     struct dcache *tdc = NULL;
589     struct conn *tc;
590     afs_int32 now, hash, new_hash, index;
591     int code = 0;
592     XSTATS_DECLS;
593
594     /* Get parent dir's FID. */
595     pdir_fid.Fid.Unique = 0;
596     afs_GetParentDirFid(avc, &pdir_fid);
597     if (!pdir_fid.Fid.Unique) {
598         printf("afs_ProcessOpCreate: Couldn't find parent dir'sFID.\n");
599         return ENOENT;
600     }
601
602     tname = afs_osi_Alloc(AFSNAMEMAX);
603     if (!tname) {
604         printf("afs_ProcessOpCreate: Couldn't find file name\n");
605         return ENOMEM;
606     }
607
608     /* Get vnode's name. */
609     code = afs_GetVnodeName(avc, &pdir_fid, tname, 0);
610     if (code) {
611         printf("afs_ProcessOpCreate: Couldn't find file name\n");
612         code = ENOENT;
613         goto end;
614     }
615
616     /* Get parent dir vcache. */
617     ObtainSharedLock(&afs_xvcache, 760);
618     tdp = afs_FindVCache(&pdir_fid, 0, 1);
619     ReleaseSharedLock(&afs_xvcache);
620     if (!tdp) {
621         printf("afs_ProcessOpCreate: Couldn't find parent dir's vcache\n");
622         code = ENOENT;
623         goto end;
624     }
625
626     if (tdp->ddirty_flags & VDisconCreate) {
627         /* If the parent dir has been created locally, defer
628          * this vnode for later by moving it to the end.
629          */
630         afs_DDirtyVCList->ddirty_next = avc;
631         afs_DDirtyVCList = avc;
632         printf("afs_ProcessOpRemove: deferring this vcache\n");
633         code = ENOTEMPTY;
634         goto end;
635     }
636
637     /* Set status. */
638     InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
639     InStatus.ClientModTime = avc->m.Date;
640     InStatus.Owner = avc->m.Owner;
641     InStatus.Group = (afs_int32) acred->cr_gid;
642     /* Only care about protection bits. */
643     InStatus.UnixModeBits = avc->m.Mode & 0xffff;
644
645     /* Connect to server. */
646     if (vType(avc) == VREG) {
647         /* Make file on server. */
648         do {
649             tc = afs_Conn(&tdp->fid, areq, SHARED_LOCK);
650             if (tc) {
651                 /* Remember for callback processing. */
652                 hostp = tc->srvr->server;
653                 now = osi_Time();
654                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
655                 RX_AFS_GUNLOCK();
656                 code = RXAFS_CreateFile(tc->id,
657                                 (struct AFSFid *)&tdp->fid.Fid,
658                                 tname,
659                                 &InStatus,
660                                 (struct AFSFid *) &newFid.Fid,
661                                 &OutFidStatus,
662                                 &OutDirStatus,
663                                 &CallBack,
664                                 &tsync);
665                 RX_AFS_GLOCK();
666                 XSTATS_END_TIME;
667                 CallBack.ExpirationTime += now;
668             } else
669                 code = -1;
670         } while (afs_Analyze(tc,
671                         code,
672                         &tdp->fid,
673                         areq,
674                         AFS_STATS_FS_RPCIDX_CREATEFILE,
675                         SHARED_LOCK,
676                         NULL));
677
678     } else if (vType(avc) == VDIR) {
679         /* Make dir on server. */
680         do {
681             tc = afs_Conn(&tdp->fid, areq, SHARED_LOCK);
682             if (tc) {
683                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_MAKEDIR);
684                 now = osi_Time();
685                 RX_AFS_GUNLOCK();
686                 code = RXAFS_MakeDir(tc->id,
687                                 (struct AFSFid *) &tdp->fid.Fid,
688                                 tname,
689                                 &InStatus,
690                                 (struct AFSFid *) &newFid.Fid,
691                                 &OutFidStatus,
692                                 &OutDirStatus,
693                                 &CallBack,
694                                 &tsync);
695                 RX_AFS_GLOCK();
696                 XSTATS_END_TIME;
697                 CallBack.ExpirationTime += now;
698                 /* DON'T forget to set the callback at some point. */
699             } else
700                code = -1;
701          } while (afs_Analyze(tc,
702                         code,
703                         &tdp->fid,
704                         areq,
705                         AFS_STATS_FS_RPCIDX_MAKEDIR,
706                         SHARED_LOCK,
707                         NULL));
708     }                                   /* Do server changes. */
709
710     /* TODO: Handle errors. */
711     if (code) {
712         printf("afs_ProcessOpCreate: error while creating vnode on server, code=%d .\n", code);
713         code = EIO;
714         goto end;
715     }
716
717     /* The rpc doesn't set the cell number. */
718     newFid.Cell = avc->fid.Cell;
719
720     /*
721      * Change the fid in the dir entry.
722      */
723
724     /* Seek the dir's dcache. */
725     tdc = afs_FindDCacheByFid(&tdp->fid);
726     if (tdc) {
727         /* And now change the fid in the parent dir entry. */
728         afs_dir_ChangeFid(tdc, tname, &avc->fid.Fid.Vnode, &newFid.Fid.Vnode);
729         afs_PutDCache(tdc);
730     }
731
732     if (vType(avc) == VDIR) {
733         /* Change fid in the dir for the "." entry. ".." has alredy been
734          * handled by afs_FixChildrenFids when processing the parent dir.
735          */
736         tdc = afs_FindDCacheByFid(&avc->fid);
737         if (tdc) {
738             afs_dir_ChangeFid(tdc, ".", &avc->fid.Fid.Vnode, &newFid.Fid.Vnode);
739
740             if (avc->m.LinkCount >= 2)
741                 /* For non empty dirs, fix children's parentVnode and parentUnique
742                  * reference.
743                  */
744                 afs_FixChildrenFids(&avc->fid, &newFid);
745
746             afs_PutDCache(tdc);
747         }
748     }
749
750     /* Recompute hash chain positions for vnode and dcaches.
751      * Then change to the new FID.
752      */
753
754     /* The vcache goes first. */
755     ObtainWriteLock(&afs_xvcache, 735);
756
757     /* Old fid hash. */
758     hash = VCHash(&avc->fid);
759     /* New fid hash. */
760     new_hash = VCHash(&newFid);
761
762     /* Remove hash from old position. */
763     /* XXX: not checking array element contents. It shouldn't be empty.
764      * If it oopses, then something else might be wrong.
765      */
766     if (afs_vhashT[hash] == avc) {
767         /* First in hash chain (might be the only one). */
768         afs_vhashT[hash] = avc->hnext;
769     } else {
770         /* More elements in hash chain. */
771         //for (tvc = afs_vhashT[hash]; tdp; tdp = tdp->hnext) {
772         for (tvc = afs_vhashT[hash]; tvc; tvc = tvc->hnext) {
773             if (tvc->hnext == avc) {
774                 tvc->hnext = avc->hnext;
775                 break;
776             }
777         }
778     }                           /* if (!afs_vhashT[i]->hnext) */
779     QRemove(&afs_vhashTV[hash]);
780
781     /* Insert hash in new position. */
782     avc->hnext = afs_vhashT[new_hash];
783     afs_vhashT[new_hash] = avc;
784     QAdd(&afs_vhashTV[new_hash], &avc->vhashq);
785
786     ReleaseWriteLock(&afs_xvcache);
787
788     /* Do the same thing for all dcaches. */
789     hash = DVHash(&avc->fid);
790     ObtainWriteLock(&afs_xdcache, 743);
791     for (index = afs_dvhashTbl[hash]; index != NULLIDX; index = hash) {
792         hash = afs_dvnextTbl[index];
793         tdc = afs_GetDSlot(index, NULL);
794         ReleaseReadLock(&tdc->tlock);
795         if (afs_indexUnique[index] == avc->fid.Fid.Unique) {
796             if (!FidCmp(&tdc->f.fid, &avc->fid)) {
797
798                 /* Safer but slower. */
799                 afs_HashOutDCache(tdc, 0);
800
801                 /* Put dcache in new positions in the dchash and dvhash. */
802                 new_hash = DCHash(&newFid, tdc->f.chunk);
803                 afs_dcnextTbl[tdc->index] = afs_dchashTbl[new_hash];
804                 afs_dchashTbl[new_hash] = tdc->index;
805
806                 new_hash = DVHash(&newFid);
807                 afs_dvnextTbl[tdc->index] = afs_dvhashTbl[new_hash];
808                 afs_dvhashTbl[new_hash] = tdc->index;
809
810                 afs_indexUnique[tdc->index] = newFid.Fid.Unique;
811                 memcpy(&tdc->f.fid, &newFid, sizeof(struct VenusFid));
812                 //afs_MaybeWakeupTruncateDaemon();
813            }                   /* if fid match */
814         }                       /* if uniquifier match */
815         if (tdc)
816             afs_PutDCache(tdc);
817     }                           /* for all dcaches in this hash bucket */
818     ReleaseWriteLock(&afs_xdcache);
819
820     /* Now we can set the new fid. */
821     memcpy(&avc->fid, &newFid, sizeof(struct VenusFid));
822
823     if (tdp) {
824         /* Unset parent dir CStat flag, so it will get refreshed on next
825          * online stat.
826          */
827         ObtainWriteLock(&tdp->lock, 745);
828         tdp->states &= ~CStatd;
829         ReleaseWriteLock(&tdp->lock);
830     }
831 end:
832     if (tdp)
833         afs_PutVCache(tdp);
834     afs_osi_Free(tname, AFSNAMEMAX);
835     return code;
836 }
837
838 /*!
839  * Remove a vnode on the server, be it file or directory.
840  * Not much to do here only get the parent dir's fid and call the
841  * removel rpc.
842  *
843  * \param avc The deleted vcache
844  * \param areq
845  *
846  * \note The vcache refcount should be dropped because it points to
847  * a deleted vnode and has served it's purpouse, but we drop refcount
848  * on shadow dir deletio (we still need it for that).
849  *
850  * \note avc must be write locked.
851  */
852 int afs_ProcessOpRemove(struct vcache *avc, struct vrequest *areq)
853 {
854     char *tname = NULL;
855     struct AFSFetchStatus OutDirStatus;
856     struct VenusFid pdir_fid;
857     struct AFSVolSync tsync;
858     struct conn *tc;
859     struct vcache *tdp = NULL;
860     int code = 0;
861     XSTATS_DECLS;
862
863     /* Get parent dir's FID. */
864     pdir_fid.Fid.Unique = 0;
865     afs_GetParentDirFid(avc, &pdir_fid);
866     if (!pdir_fid.Fid.Unique) {
867         printf("afs_ProcessOpRemove: Couldn't find parent dir's FID.\n");
868         return ENOENT;
869     }
870
871     tname = afs_osi_Alloc(AFSNAMEMAX);
872     if (!tname) {
873         printf("afs_ProcessOpRemove: Couldn't find file name\n");
874         return ENOMEM;
875     }
876
877     /* Get file name. */
878     code = afs_GetVnodeName(avc, &pdir_fid, tname, 1);
879     if (code) {
880         printf("afs_ProcessOpRemove: Couldn't find file name\n");
881         code = ENOENT;
882         goto end;
883     }
884
885     if ((vType(avc) == VDIR) && (afs_CheckDeletedChildren(avc))) {
886         /* Deleted children of this dir remain unsynchronized.
887          * Defer this vcache.
888          */
889         afs_DDirtyVCList->ddirty_next = avc;
890         afs_DDirtyVCList = avc;
891         code = ENOTEMPTY;
892         goto end;
893     }
894
895     if (vType(avc) == VREG) {
896         /* Remove file on server. */
897         do {
898             tc = afs_Conn(&pdir_fid, areq, SHARED_LOCK);
899             if (tc) {
900                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
901                 RX_AFS_GUNLOCK();
902                 code = RXAFS_RemoveFile(tc->id,
903                                 &pdir_fid.Fid,
904                                 tname,
905                                 &OutDirStatus,
906                                 &tsync);
907
908                 RX_AFS_GLOCK();
909                 XSTATS_END_TIME;
910             } else
911                 code = -1;
912         } while (afs_Analyze(tc,
913                         code,
914                         &pdir_fid,
915                         areq,
916                         AFS_STATS_FS_RPCIDX_REMOVEFILE,
917                         SHARED_LOCK,
918                         NULL));
919
920     } else if (vType(avc) == VDIR) {
921         /* Remove dir on server. */
922         do {
923             tc = afs_Conn(&pdir_fid, areq, SHARED_LOCK);
924             if (tc) {
925                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEDIR);
926                 RX_AFS_GUNLOCK();
927                 code = RXAFS_RemoveDir(tc->id,
928                                 &pdir_fid.Fid,
929                                 tname,
930                                 &OutDirStatus,
931                                 &tsync);
932                 RX_AFS_GLOCK();
933                 XSTATS_END_TIME;
934            } else
935                 code = -1;
936         } while (afs_Analyze(tc,
937                         code,
938                         &pdir_fid,
939                         areq,
940                         AFS_STATS_FS_RPCIDX_REMOVEDIR,
941                         SHARED_LOCK,
942                         NULL));
943
944     }                           /* if (vType(avc) == VREG) */
945
946     if (code)
947         printf("afs_ProcessOpRemove: server returned code=%u\n", code);
948
949     /* Remove the statd flag from parent dir's vcache. */
950     ObtainSharedLock(&afs_xvcache, 761);
951     tdp = afs_FindVCache(&pdir_fid, 0, 1);
952     ReleaseSharedLock(&afs_xvcache);
953     if (tdp) {
954         ObtainWriteLock(&tdp->lock, 746);
955         tdp->states &= ~CStatd;
956         ReleaseWriteLock(&tdp->lock);
957         afs_PutVCache(tdp);
958     }
959 end:
960     afs_osi_Free(tname, AFSNAMEMAX);
961     return code;
962 }
963
964 /*!
965  * Send disconnected file changes to the server.
966  *
967  * \note Call with vnode locked both locally and on the server.
968  *
969  * \param avc Vnode that gets synchronized to the server.
970  * \param areq Used for obtaining a conn struct.
971  *
972  * \return 0 for success. On failure, other error codes.
973  */
974 int afs_SendChanges(struct vcache *avc, struct vrequest *areq)
975 {
976     struct conn *tc;
977     struct AFSStoreStatus sstat;
978     struct AFSFetchStatus fstat;
979     struct AFSVolSync tsync;
980     int code = 0;
981     int flags = 0;
982     XSTATS_DECLS;
983
984     /* Start multiplexing dirty operations from ddirty_flags field: */
985     if (avc->ddirty_flags & VDisconSetAttrMask) {
986         /* Setattr OPS: */
987         /* Turn dirty vc data into a new store status... */
988         if (afs_GenStoreStatus(avc, &sstat) > 0) {
989             do {
990                 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
991                 if (tc) {
992                     /* ... and send it. */
993                     XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STORESTATUS);
994                     RX_AFS_GUNLOCK();
995                     code = RXAFS_StoreStatus(tc->id,
996                                 (struct AFSFid *) &avc->fid.Fid,
997                                 &sstat,
998                                 &fstat,
999                                 &tsync);
1000
1001                     RX_AFS_GLOCK();
1002                     XSTATS_END_TIME;
1003                 } else
1004                     code = -1;
1005
1006         } while (afs_Analyze(tc,
1007                         code,
1008                         &avc->fid,
1009                         areq,
1010                         AFS_STATS_FS_RPCIDX_STORESTATUS,
1011                         SHARED_LOCK,
1012                         NULL));
1013
1014         }               /* if (afs_GenStoreStatus() > 0)*/
1015     }                   /* disconnected SETATTR */
1016
1017     if (code)
1018         return code;
1019
1020     if (avc->ddirty_flags &
1021         (VDisconTrunc
1022         | VDisconWriteClose
1023         | VDisconWriteFlush
1024         | VDisconWriteOsiFlush)) {
1025
1026         /* Truncate OP: */
1027         do {
1028             tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1029             if (tc) {
1030                 /* Set storing flags. XXX: A tad inefficient ... */
1031                 if (avc->ddirty_flags & VDisconWriteClose)
1032                     flags |= AFS_LASTSTORE;
1033                 if (avc->ddirty_flags & VDisconWriteOsiFlush)
1034                     flags |= (AFS_SYNC | AFS_LASTSTORE);
1035                 if (avc->ddirty_flags & VDisconWriteFlush)
1036                     flags |= AFS_SYNC;
1037
1038                 /* Try to send store to server. */
1039                 /* XXX: AFS_LASTSTORE for writes? Or just AFS_SYNC for all? */
1040                 code = afs_StoreAllSegments(avc, areq, flags);
1041             } else
1042                 code = -1;
1043
1044         } while (afs_Analyze(tc,
1045                         code,
1046                         &avc->fid,
1047                         areq,
1048                         AFS_STATS_FS_RPCIDX_STOREDATA,
1049                         SHARED_LOCK,
1050                         NULL));
1051
1052     }                   /* disconnected TRUNC | WRITE */
1053
1054     return code;
1055 }
1056
1057 /*!
1058  * All files that have been dirty before disconnection are going to
1059  * be replayed back to the server.
1060  *
1061  * \param areq Request from the user.
1062  * \param acred User credentials.
1063  *
1064  * \return If all files synchronized succesfully, return 0, otherwise
1065  * return 1.
1066  *
1067  * \note For now, it's the request from the PDiscon pioctl.
1068  *
1069  */
1070 int afs_ResyncDisconFiles(struct vrequest *areq, struct AFS_UCRED *acred)
1071 {
1072     struct conn *tc;
1073     struct vcache *tvc, *tmp;
1074     struct AFSFetchStatus fstat;
1075     struct AFSCallBack callback;
1076     struct AFSVolSync tsync;
1077     struct vcache *shList, *shListStart;
1078     int code;
1079     int sync_failed = 0;
1080     int ret_code = 0;
1081     int defered = 0;
1082     afs_int32 start = 0;
1083     XSTATS_DECLS;
1084     //AFS_STATCNT(afs_ResyncDisconFiles);
1085
1086     shList = shListStart = NULL;
1087
1088     ObtainReadLock(&afs_DDirtyVCListLock);
1089
1090     tvc = afs_DDirtyVCListStart;
1091     while (tvc) {
1092
1093         /* Get local write lock. */
1094         ObtainWriteLock(&tvc->lock, 704);
1095         sync_failed = 0;
1096
1097         if ((tvc->ddirty_flags & VDisconRemove) &&
1098             (tvc->ddirty_flags & VDisconCreate)) {
1099            /* Data created and deleted locally. The server doesn't
1100             * need to know about this, so we'll just skip this file
1101             * from the dirty list.
1102             */
1103             goto skip_file;
1104
1105         } else if (tvc->ddirty_flags & VDisconRemove) {
1106             /* Delete the file on the server and just move on
1107              * to the next file. After all, it has been deleted
1108              * we can't replay any other operation it.
1109              */
1110             code = afs_ProcessOpRemove(tvc, areq);
1111             if (code == ENOTEMPTY)
1112                 defered = 1;
1113             goto skip_file;
1114
1115         } else if (tvc->ddirty_flags & VDisconCreate) {
1116             /* For newly created files, we don't need a server lock. */
1117             code = afs_ProcessOpCreate(tvc, areq, acred);
1118             if (code == ENOTEMPTY)
1119                 defered = 1;
1120             if (code)
1121                 goto skip_file;
1122         }
1123
1124         /* Get server write lock. */
1125         do {
1126             tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
1127             if (tc) {
1128                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETLOCK);
1129                 RX_AFS_GUNLOCK();
1130                 code = RXAFS_SetLock(tc->id,
1131                                         (struct AFSFid *)&tvc->fid.Fid,
1132                                         LockWrite,
1133                                         &tsync);
1134                 RX_AFS_GLOCK();
1135                 XSTATS_END_TIME;
1136            } else
1137                 code = -1;
1138
1139         } while (afs_Analyze(tc,
1140                         code,
1141                         &tvc->fid,
1142                         areq,
1143                         AFS_STATS_FS_RPCIDX_SETLOCK,
1144                         SHARED_LOCK,
1145                         NULL));
1146
1147         if (code) {
1148             sync_failed = 1;
1149             goto skip_file;
1150         }
1151
1152         if ((tvc->ddirty_flags & VDisconRename) &&
1153                 !(tvc->ddirty_flags & VDisconCreate)) {
1154             /* Rename file only if it hasn't been created locally. */
1155             code = afs_ProcessOpRename(tvc, areq);
1156             if (code)
1157                 goto skip_file;
1158         }
1159
1160         /* Issue a FetchStatus to get info about DV and callbacks. */
1161         do {
1162             tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
1163             if (tc) {
1164                 tvc->callback = tc->srvr->server;
1165                 start = osi_Time();
1166                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
1167                 RX_AFS_GUNLOCK();
1168                 code = RXAFS_FetchStatus(tc->id,
1169                                 (struct AFSFid *)&tvc->fid.Fid,
1170                                 &fstat,
1171                                 &callback,
1172                                 &tsync);
1173                 RX_AFS_GLOCK();
1174                 XSTATS_END_TIME;
1175             } else
1176                 code = -1;
1177
1178         } while (afs_Analyze(tc,
1179                         code,
1180                         &tvc->fid,
1181                         areq,
1182                         AFS_STATS_FS_RPCIDX_FETCHSTATUS,
1183                         SHARED_LOCK,
1184                         NULL));
1185
1186         if (code) {
1187             sync_failed = 1;
1188             goto unlock_srv_file;
1189         }
1190
1191         if ((dv_match(tvc, fstat) && (tvc->m.Date == fstat.ServerModTime)) ||
1192                 (afs_ConflictPolicy == CLIENT_WINS) ||
1193                 (tvc->ddirty_flags & VDisconCreate)) {
1194             /*
1195              * Send changes to the server if there's data version match, or
1196              * client wins policy has been selected or file has been created
1197              * but doesn't have it's the contents on to the server yet.
1198              */
1199            /*
1200             * XXX: Checking server attr changes by timestamp might not the
1201             * most elegant solution, but it's the most viable one that we could find.
1202             */
1203             afs_UpdateStatus(tvc, &tvc->fid, areq, &fstat, &callback, start);
1204             code = afs_SendChanges(tvc, areq);
1205
1206         } else if (afs_ConflictPolicy == SERVER_WINS) {
1207             /* DV mismatch, apply collision resolution policy. */
1208             /* Dequeue whatever callback is on top (XXX: propably none). */
1209             ObtainWriteLock(&afs_xcbhash, 706);
1210             afs_DequeueCallback(tvc);
1211             tvc->callback = NULL;
1212             tvc->states &= ~(CStatd | CDirty | CUnique);
1213             ReleaseWriteLock(&afs_xcbhash);
1214
1215             /* Save metadata. File length gets updated as well because we
1216              * just removed CDirty from the avc.
1217              */
1218             //afs_ProcessFS(tvc, &fstat, areq);
1219
1220             /* Discard this files chunks and remove from current dir. */
1221             afs_TryToSmush(tvc, acred, 1);
1222             osi_dnlc_purgedp(tvc);
1223             if (tvc->linkData && !(tvc->states & CCore)) {
1224                 /* Take care of symlinks. */
1225                 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
1226                 tvc->linkData = NULL;
1227             }
1228
1229             /* Otherwise file content's won't be synchronized. */
1230             tvc->truncPos = AFS_NOTRUNC;
1231
1232         } else {
1233             printf("afs_ResyncDisconFiles: no resolution policy selected.\n");
1234         }               /* if DV match or client wins policy */
1235
1236         if (code) {
1237             sync_failed = 1;
1238             printf("Sync FAILED.\n");
1239         }
1240
1241 unlock_srv_file:
1242         /* Release server write lock. */
1243         do {
1244             tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
1245             if (tc) {
1246                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
1247                 RX_AFS_GUNLOCK();
1248                 code = RXAFS_ReleaseLock(tc->id,
1249                                 (struct AFSFid *) &tvc->fid.Fid,
1250                                 &tsync);
1251                 RX_AFS_GLOCK();
1252                 XSTATS_END_TIME;
1253             } else
1254                 code = -1;
1255         } while (afs_Analyze(tc,
1256                         code,
1257                         &tvc->fid,
1258                         areq,
1259                         AFS_STATS_FS_RPCIDX_RELEASELOCK,
1260                         SHARED_LOCK,
1261                         NULL));
1262
1263 skip_file:
1264         /* Pop this dirty vc out. */
1265         tmp = tvc;
1266         tvc = tvc->ddirty_next;
1267
1268         if (!defered) {
1269             /* Vnode not deferred. Clean it up. */
1270             if (!sync_failed) {
1271                 if (tmp->ddirty_flags == VDisconShadowed) {
1272                     /* Dirs that have only the shadow flag set might still
1273                      * be used so keep them in a different list, that gets
1274                      * deleted after resync is done.
1275                      */
1276                     if (!shListStart)
1277                         shListStart = shList = tmp;
1278                     else {
1279                         shList->ddirty_next = tmp;
1280                         shList = tmp;
1281                     }
1282                 } else if (tmp->ddirty_flags & VDisconShadowed)
1283                     /* We can discard the shadow dir now. */
1284                     afs_DeleteShadowDir(tmp);
1285
1286                 if (tmp->ddirty_flags & VDisconRemove)
1287                     /* Drop the refcount on the deleted vnodes,
1288                      * because we don't need them anymore.
1289                      */
1290                     afs_PutVCache(tmp);
1291
1292                 /* Only if sync was successfull,
1293                  * clear flags and dirty references.
1294                  */
1295                 tmp->ddirty_next = NULL;
1296                 tmp->ddirty_flags = 0;
1297             } else
1298                 ret_code = 1;
1299         } else {
1300             tmp->ddirty_next = NULL;
1301             defered = 0;
1302         }                       /* if (!defered) */
1303
1304         /* Release local write lock. */
1305         ReleaseWriteLock(&tmp->lock);
1306     }                   /* while (tvc) */
1307
1308     /* Delete the rest of shadow dirs. */
1309     tvc = shListStart;
1310     while (tvc) {
1311         ObtainWriteLock(&tvc->lock, 764);
1312
1313         afs_DeleteShadowDir(tvc);
1314         tvc->shVnode = 0;
1315         tvc->shUnique = 0;
1316
1317         tmp = tvc;
1318         tvc = tvc->ddirty_next;
1319         tmp->ddirty_next = NULL;
1320
1321         ReleaseWriteLock(&tmp->lock);
1322     }                           /* while (tvc) */
1323
1324     if (ret_code == 0) {
1325         /* NULLIFY dirty list only if resync complete. */
1326         afs_DDirtyVCListStart = NULL;
1327         afs_DDirtyVCList = NULL;
1328     }
1329     ReleaseReadLock(&afs_DDirtyVCListLock);
1330
1331     return ret_code;
1332 }
1333
1334 /*!
1335  * Print list of disconnected files.
1336  *
1337  * \note Call with afs_DDirtyVCListLock read locked.
1338  */
1339 void afs_DbgDisconFiles()
1340 {
1341     struct vcache *tvc;
1342     int i = 0;
1343
1344     tvc = afs_DDirtyVCListStart;
1345     printf("List of dirty files: \n");
1346     while (tvc) {
1347         printf("Cell=%u Volume=%u VNode=%u Unique=%u\n",
1348                 tvc->fid.Cell,
1349                 tvc->fid.Fid.Volume,
1350                 tvc->fid.Fid.Vnode,
1351                 tvc->fid.Fid.Unique);
1352         tvc = tvc->ddirty_next;
1353         i++;
1354         if (i >= 30)
1355             osi_Panic("afs_DbgDisconFiles: loop in dirty list\n");
1356     }
1357 }
1358
1359 /*!
1360  * Generate a fake fid for a disconnected shadow dir.
1361  * Similar to afs_GenFakeFid, only that it uses the dhash
1362  * to search for a uniquifier because a shadow dir lives only
1363  * in the dcache.
1364  *
1365  * \param afid
1366  *
1367  * \note Don't forget to fill in afid with Cell and Volume.
1368  */
1369 void afs_GenShadowFid(struct VenusFid *afid)
1370 {
1371     afs_uint32 i, index, max_unique = 1;
1372     struct vcache *tvc = NULL;
1373
1374     /* Try generating a fid that isn't used in the vhash. */
1375     do {
1376         afid->Fid.Vnode = afs_DisconVnode + 1;
1377
1378         i = DVHash(afid);
1379         ObtainWriteLock(&afs_xdcache, 737);
1380         for (index = afs_dvhashTbl[i]; index != NULLIDX; index = i) {
1381             i = afs_dvnextTbl[index];
1382             if (afs_indexUnique[index] > max_unique)
1383                 max_unique = afs_indexUnique[index];
1384         }
1385
1386         ReleaseWriteLock(&afs_xdcache);
1387         afid->Fid.Unique = max_unique + 1;
1388         afs_DisconVnode += 2;
1389         if (!afs_DisconVnode)
1390             afs_DisconVnode = 2;
1391
1392         /* Is this a used vnode? */
1393         ObtainSharedLock(&afs_xvcache, 762);
1394         tvc = afs_FindVCache(afid, 0, 1);
1395         ReleaseSharedLock(&afs_xvcache);
1396         if (tvc)
1397             afs_PutVCache(tvc);
1398     } while (tvc);
1399 }
1400
1401 /*!
1402  * Generate a fake fid (vnode and uniquifier) for a vcache
1403  * (either dir or normal file). The vnode is generated via
1404  * afs_DisconVNode and the uniquifier by getting the highest
1405  * uniquifier on a hash chain and incrementing it by one.
1406  *
1407  * \param avc afid The fid structre that will be filled.
1408  * \param avtype Vnode type: VDIR/VREG.
1409  *
1410  * \note The cell number must be completed somewhere else.
1411  */
1412 void afs_GenFakeFid(struct VenusFid *afid, afs_uint32 avtype)
1413 {
1414     struct vcache *tvc;
1415     afs_uint32 max_unique = 1, i;
1416
1417     if (avtype == VDIR)
1418         afid->Fid.Vnode = afs_DisconVnode + 1;
1419     else if (avtype == VREG)
1420         afid->Fid.Vnode = afs_DisconVnode;
1421
1422     ObtainWriteLock(&afs_xvcache, 736);
1423     i = VCHash(afid);
1424     for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
1425         if (tvc->fid.Fid.Unique > max_unique)
1426             max_unique = tvc->fid.Fid.Unique;
1427     }
1428     ReleaseWriteLock(&afs_xvcache);
1429
1430     afid->Fid.Unique = max_unique + 1;
1431     afs_DisconVnode += 2;
1432     if (!afs_DisconVnode)
1433         afs_DisconVnode = 2;
1434 }
1435
1436 /*!
1437  * Fill in stats for a newly created file/directory.
1438  *
1439  * \param adp The parent dir's vcache.
1440  * \param avc The created vnode.
1441  * \param afid The new fid.
1442  * \param attrs
1443  * \param areq
1444  * \param file_type Specify if file or directory.
1445  *
1446  * \note Call with avc write locked.
1447  */
1448 void afs_GenDisconStatus(
1449         struct vcache *adp,
1450         struct vcache *avc,
1451         struct VenusFid *afid,
1452         struct vattr *attrs,
1453         struct vrequest *areq,
1454         int file_type)
1455 {
1456     memcpy(&avc->fid, afid, sizeof(struct VenusFid));
1457     avc->m.Mode = attrs->va_mode;
1458     /* Used to do this:
1459      * avc->m.Owner = attrs->va_uid;
1460      * But now we use the parent dir's ownership,
1461      * there's no other way to get a server owner id.
1462      * XXX: Does it really matter?
1463      */
1464     avc->m.Group = adp->m.Group;
1465     avc->m.Owner = adp->m.Owner;
1466     hset64(avc->m.DataVersion, 0, 0);
1467     avc->m.Length = attrs->va_size;
1468     avc->m.Date = osi_Time();
1469     if (file_type == VREG) {
1470         vSetType(avc, VREG);
1471         avc->m.Mode |= S_IFREG;
1472         avc->m.LinkCount = 1;
1473     } else if (file_type == VDIR) {
1474         vSetType(avc, VDIR);
1475         avc->m.Mode |= S_IFDIR;
1476         avc->m.LinkCount = 2;
1477     }
1478
1479     avc->anyAccess = adp->anyAccess;
1480     afs_AddAxs(avc->Access, areq->uid, adp->Access->axess);
1481
1482     avc->callback = NULL;
1483     avc->states |= CStatd;
1484     avc->states &= ~CBulkFetching;
1485 }
1486 #endif