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