2 * Copyright (c) 1995 - 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * This is the cache for files.
36 * The hash-table is keyed with (cell, volume, fid).
39 #include "arla_local.h"
50 static int get_attr_bulk (FCacheEntry
*parent_entry
,
51 FCacheEntry
*prefered_entry
,
52 VenusFid
*prefered_fid
,
53 const char *prefered_name
,
57 resolve_mp (FCacheEntry
**e
, VenusFid
*ret_fid
, CredCacheEntry
**ce
);
60 * Local data for this module.
64 * Hash table for all the vnodes known by the cache manager keyed by
65 * (cell, volume, vnode, unique).
68 static Hashtab
*hashtab
;
71 * List of all hash table entries. This list is sorted in LRU-order.
72 * The head is the MRU and the tail the LRU, which is from where we
73 * take entries when we need to add new ones.
79 * Heap of entries to be invalidated.
82 static Heap
*invalid_heap
;
84 /* low and high-water marks for vnodes and space */
86 static u_long highvnodes
, lowvnodes
, current_vnodes
;
87 static int64_t highbytes
, lowbytes
;
91 static int64_t usedbytes
, needbytes
;
92 static u_long usedvnodes
;
94 /* Map with recovered nodes */
96 static u_long maxrecovered
;
98 static char *recovered_map
;
101 set_recovered(u_long index
)
106 if (index
>= maxrecovered
) {
107 oldmax
= maxrecovered
;
108 maxrecovered
= (index
+ 16) * 2;
109 p
= realloc(recovered_map
, maxrecovered
);
111 arla_errx(1, ADEBERROR
, "fcache: realloc %lu recovered_map failed",
115 memset(recovered_map
+ oldmax
, 0, maxrecovered
- oldmax
);
117 recovered_map
[index
] = 1;
120 #define IS_RECOVERED(index) (recovered_map[(index)])
123 * This is how far the cleaner will go to clean out entries.
124 * The higher this is, the higher the risk is that you will
125 * loose any file that you feel is important to disconnected
129 Bool fprioritylevel
= arla_FPRIO_DEFAULT
;
131 static int node_count
; /* XXX */
134 * This is set to non-zero when we want to use bulkstatus(). 2 means
135 * that the nodes should be installed into the kernel.
138 static int fcache_enable_bulkstatus
= 1;
139 static int fcache_bulkstatus_num
= 14; /* XXX should use the [P]MTU */
141 #define FCHASHSIZE 997
147 #define CLEANER_SLEEP 10
149 static PROCESS cleaner_pid
;
152 * The creator of nodes.
155 static PROCESS create_nodes_pid
;
161 static PROCESS invalidator_pid
;
164 * Smalltalk emulation
168 fcache_highbytes(void)
174 fcache_usedbytes(void)
180 fcache_lowbytes(void)
186 fcache_highvnodes(void)
192 fcache_usedvnodes(void)
198 fcache_lowvnodes(void)
208 unsigned long fetch_attr
;
209 unsigned long fetch_attr_cached
;
210 unsigned long fetch_attr_bulk
;
211 unsigned long fetch_data
;
212 unsigned long fetch_data_cached
;
213 unsigned long store_attr
;
214 unsigned long store_data
;
218 * Compare two entries. Return 0 if and only if the same.
222 fcachecmp (void *a
, void *b
)
224 FCacheEntry
*f1
= (FCacheEntry
*)a
;
225 FCacheEntry
*f2
= (FCacheEntry
*)b
;
227 return VenusFid_cmp(&f1
->fid
, &f2
->fid
);
231 * Hash the value of an entry.
237 FCacheEntry
*f
= (FCacheEntry
*)e
;
239 return f
->fid
.Cell
+ f
->fid
.fid
.Volume
+ f
->fid
.fid
.Vnode
244 * Compare expiration times.
248 expiration_time_cmp (const void *a
, const void *b
)
250 const FCacheEntry
*f1
= (const FCacheEntry
*)a
;
251 const FCacheEntry
*f2
= (const FCacheEntry
*)b
;
253 return f1
->callback
.ExpirationTime
- f2
->callback
.ExpirationTime
;
257 recon_hashtabadd(FCacheEntry
*entry
)
259 hashtabadd(hashtab
,entry
);
263 recon_hashtabdel(FCacheEntry
*entry
)
265 hashtabdel(hashtab
,entry
);
272 char **sysnamelist
= NULL
;
280 fcache_poller_unref(FCacheEntry
*e
)
282 AssertExclLocked(&e
->lock
);
285 poller_remove(e
->poll
);
291 fcache_poller_reref(FCacheEntry
*e
, ConnCacheEntry
*conn
)
293 PollerEntry
*pe
= e
->poll
;
294 AssertExclLocked(&e
->lock
);
296 e
->poll
= poller_add_conn(conn
);
307 fcache_getdefsysname (void)
310 return "fool-dont-remove-all-sysnames";
311 return sysnamelist
[0];
319 fcache_setdefsysname (const char *sysname
)
322 return fcache_addsysname (sysname
);
323 free (sysnamelist
[0]);
324 sysnamelist
[0] = estrdup (sysname
);
333 fcache_addsysname (const char *sysname
)
336 sysnamelist
= erealloc (sysnamelist
,
337 sysnamenum
* sizeof(char *));
338 sysnamelist
[sysnamenum
- 1] = estrdup(sysname
);
347 fcache_removesysname (const char *sysname
)
350 for (i
= 0; i
< sysnamenum
; i
++)
351 if (strcmp (sysnamelist
[i
], sysname
) == 0)
355 free (sysnamelist
[i
]);
356 for (;i
< sysnamenum
; i
++)
357 sysnamelist
[i
] = sysnamelist
[i
+ 1];
359 sysnamelist
= erealloc (sysnamelist
,
360 sysnamenum
* sizeof(char *));
365 * return the directory name of the cached file for `entry'
369 fcache_dir_name (FCacheEntry
*entry
, char *s
, size_t len
)
371 return snprintf (s
, len
, "%02X", entry
->index
/ 0x100);
375 * return the file name of the cached file for `entry'.
379 fcache_file_name (FCacheEntry
*entry
, char *s
, size_t len
)
381 return snprintf (s
, len
, "%02X/%02X",
382 entry
->index
/ 0x100, entry
->index
% 0x100);
386 * return kernel version of path to the cache file for `entry'.
390 fcache_conv_file_name (FCacheEntry
*entry
, char *s
, size_t len
)
394 GetCurrentDirectory(1024, buf
);
396 return snprintf (s
, len
, "%s\\%02X\\%02X",
397 buf
, entry
->index
/ 0x100, entry
->index
% 0x100);
399 return snprintf (s
, len
, "%02X/%02X",
400 entry
->index
/ 0x100, entry
->index
% 0x100);
405 * the filename for the extra (converted) directory
409 real_extra_file_name (FCacheEntry
*entry
, char *s
, size_t len
)
413 ret
= fcache_file_name (entry
, s
, len
- 1);
422 * return the file name of the converted directory for `entry'.
426 fcache_extra_file_name (FCacheEntry
*entry
, char *s
, size_t len
)
428 assert (entry
->flags
.extradirp
&&
429 entry
->status
.FileType
== TYPE_DIR
);
431 return real_extra_file_name (entry
, s
, len
);
434 static int fhopen_working
;
437 * open file by handle
441 fcache_fhopen (fcache_cache_handle
*handle
, int flags
)
443 if (!handle
->valid
) {
452 #if defined(HAVE_GETFH) && defined(HAVE_FHOPEN)
457 memcpy (&fh
, &handle
->nnpfs_handle
, sizeof(fh
));
458 ret
= fhopen (&fh
, flags
);
464 #ifdef KERBEROS /* really KAFS */
466 struct arlaViceIoctl vice_ioctl
;
468 vice_ioctl
.in
= (caddr_t
)&handle
->nnpfs_handle
;
469 vice_ioctl
.in_size
= sizeof(handle
->nnpfs_handle
);
471 vice_ioctl
.out
= NULL
;
472 vice_ioctl
.out_size
= 0;
474 return k_pioctl (NULL
, ARLA_VIOC_FHOPEN
, (void *)&vice_ioctl
, flags
);
483 * get the handle of `filename'
487 fcache_fhget (char *filename
, fcache_cache_handle
*handle
)
496 ret
= sscanf(filename
, "%02X/%02X", &a
, &b
);
500 GetCurrentDirectory(sizeof(buf
)-1, buf
);
501 buf
[sizeof(buf
) - 1] = '\0';
503 ret
= snprintf((char *)handle
->nnpfs_handle
,
504 sizeof(handle
->nnpfs_handle
),
505 "%s\\%02X\\%02X", buf
, a
, b
);
507 if (ret
> 0 || ret
< sizeof(handle
->nnpfs_handle
))
514 #if defined(HAVE_GETFH) && defined(HAVE_FHOPEN)
519 ret
= getfh (filename
, &fh
);
521 memcpy (&handle
->nnpfs_handle
, &fh
, sizeof(fh
));
530 struct arlaViceIoctl vice_ioctl
;
536 vice_ioctl
.in
= NULL
;
537 vice_ioctl
.in_size
= 0;
539 vice_ioctl
.out
= (caddr_t
)&handle
->nnpfs_handle
;
540 vice_ioctl
.out_size
= sizeof(handle
->nnpfs_handle
);
542 ret
= k_pioctl (filename
, ARLA_VIOC_FHGET
, (void *)&vice_ioctl
, 0);
555 * create a new cache vnode, assume the entry is locked or private
559 fcache_create_file (FCacheEntry
*entry
, int create
)
561 char fname
[MAXPATHLEN
];
562 char extra_fname
[MAXPATHLEN
];
566 int largefileflag
= 0;
569 largefileflag
= O_LARGEFILE
;
571 flags
= O_RDWR
| O_BINARY
| largefileflag
;
574 flags
|= O_CREAT
| O_TRUNC
;
576 fcache_file_name (entry
, fname
, sizeof(fname
));
577 fd
= open (fname
, flags
, 0666);
579 if (errno
== ENOENT
&& create
) {
580 char dname
[MAXPATHLEN
];
582 fcache_dir_name (entry
, dname
, sizeof(dname
));
583 ret
= mkdir (dname
, 0777);
585 arla_err (1, ADEBERROR
, errno
, "mkdir %s", dname
);
586 fd
= open (fname
, flags
, 0666);
588 arla_err (1, ADEBERROR
, errno
, "open %s", fname
);
590 arla_err (1, ADEBERROR
, errno
, "open %s", fname
);
594 arla_err (1, ADEBERROR
, errno
, "close %s", fname
);
595 fcache_fhget (fname
, &entry
->handle
);
596 real_extra_file_name (entry
, extra_fname
, sizeof(extra_fname
));
597 unlink (extra_fname
);
602 * return a fd to the cache file of `entry'
606 fcache_open_file (FCacheEntry
*entry
, int flag
)
609 char fname
[MAXPATHLEN
];
610 int largefileflag
= 0;
613 largefileflag
= O_LARGEFILE
;
615 if (fhopen_working
) {
616 ret
= fcache_fhopen (&entry
->handle
, flag
| largefileflag
);
617 if (ret
< 0 && (errno
== EINVAL
|| errno
== EPERM
))
622 fcache_file_name (entry
, fname
, sizeof(fname
));
623 return open (fname
, flag
| O_BINARY
| largefileflag
);
627 * return a fd to the converted directory for `entry'
631 fcache_open_extra_dir (FCacheEntry
*entry
, int flag
, mode_t mode
)
633 char fname
[MAXPATHLEN
];
635 assert (entry
->flags
.extradirp
&&
636 entry
->status
.FileType
== TYPE_DIR
);
638 fcache_extra_file_name (entry
, fname
, sizeof(fname
));
639 return open (fname
, flag
| O_BINARY
, mode
);
647 fcache_get_status_length(const AFSFetchStatus
*status
)
649 return status
->Length
| ((uint64_t)status
->LengthHigh
<< 32);
653 fcache_set_status_length(AFSFetchStatus
*status
, int64_t length
)
655 status
->Length
= length
& 0xffffffff;
656 status
->LengthHigh
= length
>> 32;
661 * Discard the data cached for `entry'.
665 throw_data (FCacheEntry
*entry
)
670 assert (entry
->flags
.usedp
);
671 AssertExclLocked(&entry
->lock
);
673 fd
= fcache_open_file (entry
, O_WRONLY
);
675 arla_warn (ADEBFCACHE
, errno
, "fcache_open_file");
678 if (fstat (fd
, &sb
) < 0) {
679 arla_warn (ADEBFCACHE
, errno
, "fstat");
683 if (ftruncate (fd
, 0) < 0) {
684 arla_warn (ADEBFCACHE
, errno
, "ftruncate");
689 if (entry
->flags
.extradirp
) {
690 char fname
[MAXPATHLEN
];
692 fcache_extra_file_name (entry
, fname
, sizeof(fname
));
695 assert(usedbytes
>= entry
->length
);
696 /* XXX - things are wrong - continue anyway */
697 if (usedbytes
< entry
->length
)
698 usedbytes
= entry
->length
;
699 usedbytes
-= entry
->length
;
701 entry
->wanted_length
= 0;
702 entry
->fetched_length
= 0;
703 entry
->flags
.extradirp
= FALSE
;
706 cm_check_consistency();
710 * A probe function for a file server.
714 fs_probe (struct rx_connection
*conn
)
718 return RXAFS_GetTime (conn
, &sec
, &usec
);
726 throw_entry (FCacheEntry
*entry
)
729 ConnCacheEntry
*conn
;
734 assert (entry
->flags
.usedp
);
735 assert (!entry
->flags
.kernelp
);
737 AssertExclLocked(&entry
->lock
);
738 assert(LockWaiters(&entry
->lock
) == 0);
740 hashtabdel (hashtab
, entry
);
743 * Throw data when there is any, length is a good test since the
744 * node must not be used (in kernel) when we get here.
749 if (entry
->invalid_ptr
!= -1) {
750 heap_remove (invalid_heap
, entry
->invalid_ptr
);
751 entry
->invalid_ptr
= -1;
754 fcache_poller_unref(entry
);
756 if (entry
->flags
.attrp
&& !entry
->flags
.silly
&& entry
->host
) {
757 ce
= cred_get (entry
->fid
.Cell
, 0, CRED_NONE
);
760 conn
= conn_get (entry
->fid
.Cell
, entry
->host
, afsport
,
761 FS_SERVICE_ID
, fs_probe
, ce
);
764 fids
.len
= cbs
.len
= 1;
765 fids
.val
= &entry
->fid
.fid
;
766 cbs
.val
= &entry
->callback
;
768 if (conn_isalivep (conn
)) {
769 ret
= RXAFS_GiveUpCallBacks(conn
->connection
, &fids
, &cbs
);
770 if (host_downp(ret
)) {
778 arla_warn (ADEBFCACHE
, ret
, "RXAFS_GiveUpCallBacks");
781 volcache_free (entry
->volume
);
782 entry
->volume
= NULL
;
784 assert_not_flag(entry
,kernelp
);
785 entry
->flags
.attrp
= FALSE
;
786 entry
->flags
.usedp
= FALSE
;
788 LWP_NoYieldSignal (lrulist
);
792 * Return the next cache node number.
796 next_cache_index (void)
800 } while ((node_count
< maxrecovered
)
801 && IS_RECOVERED(node_count
));
807 * Pre-create cache nodes up to the limit highvnodes. If you want to
808 * create more increase highnodes and signal create_nodes.
812 create_nodes (char *arg
)
814 FCacheEntry
*entries
;
819 unsigned int n
, i
, j
;
821 while (highvnodes
<= current_vnodes
)
822 LWP_WaitProcess (create_nodes
);
824 n
= highvnodes
- current_vnodes
;
828 arla_warnx (ADEBFCACHE
,
829 "pre-creating nodes");
831 entries
= calloc (n
, sizeof(FCacheEntry
));
832 if (n
!= 0 && entries
== NULL
)
833 arla_errx (1, ADEBERROR
, "fcache: calloc failed");
835 for (i
= 0; i
< n
; ++i
) {
836 entries
[i
].invalid_ptr
= -1;
837 entries
[i
].volume
= NULL
;
838 entries
[i
].refcount
= 0;
839 entries
[i
].anonaccess
= 0;
840 entries
[i
].cleanergen
= 0;
841 entries
[i
].poll
= NULL
;
842 for (j
= 0; j
< NACCESS
; j
++) {
843 entries
[i
].acccache
[j
].cred
= ARLA_NO_AUTH_CRED
;
844 entries
[i
].acccache
[j
].access
= 0;
846 entries
[i
].length
= 0;
847 Lock_Init(&entries
[i
].lock
);
848 entries
[i
].index
= next_cache_index ();
849 fcache_create_file (&entries
[i
], 1);
857 entries
[i
].lru_le
= listaddhead (lrulist
, &entries
[i
]);
858 assert (entries
[i
].lru_le
);
860 LWP_NoYieldSignal (lrulist
);
861 IOMGR_Select(0, NULL
, NULL
, NULL
, &tv
);
864 arla_warnx (ADEBFCACHE
,
865 "pre-created %u nodes", count
);
870 * This is the almighty cleaner loop
873 static Bool cleaner_working
= FALSE
;
878 enum { CL_OPPORTUNISTIC
, CL_FORCE
, CL_COLLECT
} state
;
879 int cnt
= 0, numnodes
;
883 numnodes
= NNPFS_GC_NODES_MAX_HANDLE
;
885 fids
= malloc (sizeof(*fids
) * numnodes
);
887 arla_err (1, ADEBERROR
, errno
, "cleaner: malloc");
890 Listitem
*item
, *prev
;
893 arla_warnx (ADEBCLEANER
,
895 "%lu (%lu-(%lu)-%lu) files, "
896 "%lu (%lu-%lu) bytes "
898 usedvnodes
, lowvnodes
, current_vnodes
, highvnodes
,
899 (long)usedbytes
, (long)lowbytes
, (long)highbytes
,
902 cleaner_working
= TRUE
;
904 state
= CL_OPPORTUNISTIC
;
907 while (usedvnodes
> lowvnodes
908 || usedbytes
> lowbytes
909 || needbytes
> highbytes
- usedbytes
)
912 for (item
= listtail (lrulist
);
914 (usedvnodes
> lowvnodes
915 || usedbytes
> lowbytes
916 || needbytes
> highbytes
- usedbytes
);
918 prev
= listprev (lrulist
, item
);
919 entry
= (FCacheEntry
*)listdata (item
);
921 if (fprioritylevel
&& entry
->priority
)
924 if (entry
->cleanergen
== cleanerrun
)
926 entry
->cleanergen
= cleanerrun
;
928 if (entry
->flags
.usedp
929 && (usedvnodes
> lowvnodes
930 || usedbytes
> lowbytes
931 || needbytes
> highbytes
- usedbytes
)
932 && entry
->refcount
== 0
933 && CheckLock(&entry
->lock
) == 0)
935 if (!entry
->flags
.datausedp
936 && !entry
->flags
.kernelp
937 /* && this_is_a_good_node_to_gc(entry,state) */) {
939 ObtainWriteLock (&entry
->lock
);
940 listdel (lrulist
, item
);
942 entry
->lru_le
= listaddtail (lrulist
, entry
);
943 assert(entry
->lru_le
);
944 ReleaseWriteLock (&entry
->lock
);
948 if (state
== CL_FORCE
&& entry
->flags
.kernelp
) {
950 fids
[cnt
++] = entry
->fid
;
952 if (cnt
>= numnodes
) {
953 nnpfs_send_message_gc_nodes (kernel_fd
, cnt
, fids
);
960 assert (entry
->lru_le
== item
);
964 case CL_OPPORTUNISTIC
:
966 LWP_DispatchProcess(); /* Yield */
971 nnpfs_send_message_gc_nodes (kernel_fd
, cnt
, fids
);
987 arla_warnx(ADEBCLEANER
,
989 "%lu (%lu-(%lu)-%lu) files, "
990 "%ld (%ld-%ld) bytes "
992 usedvnodes
, lowvnodes
, current_vnodes
, highvnodes
,
993 (long)usedbytes
, (long)lowbytes
, (long)highbytes
,
996 cm_check_consistency();
998 LWP_NoYieldSignal (fcache_need_bytes
);
999 cleaner_working
= FALSE
;
1000 IOMGR_Sleep (CLEANER_SLEEP
);
1005 fcache_wakeup_cleaner (void *wait
)
1007 if (cleaner_working
== FALSE
)
1008 IOMGR_Cancel (cleaner_pid
);
1009 LWP_WaitProcess (wait
);
1013 fcache_need_bytes (u_long needed
)
1015 if (needed
+ needbytes
> highbytes
) {
1016 arla_warnx (ADEBWARN
,
1017 "Out of space since there is outstanding requests "
1018 "(%ld needed, %ld outstanding, %ld highbytes)",
1019 (long)needed
, (long)needbytes
, (long)highbytes
);
1023 needbytes
+= needed
;
1024 fcache_wakeup_cleaner(fcache_need_bytes
);
1025 needbytes
-= needed
;
1026 if (needed
> highbytes
- usedbytes
) {
1027 arla_warnx (ADEBWARN
,
1028 "Out of space, couldn't get needed bytes after cleaner "
1029 "(%lu bytes missing, %lu used, %lu highbytes)",
1030 (long)(needed
- (highbytes
- usedbytes
)),
1031 (long)usedbytes
, (long)highbytes
);
1038 fcache_need_nodes (void)
1040 fcache_wakeup_cleaner (lrulist
);
1041 if (current_vnodes
== usedvnodes
)
1048 * Run through the heap of objects to be invalidated and throw them away
1049 * when their expirationtime arrive.
1053 invalidator (char *arg
)
1059 arla_warnx(ADEBINVALIDATOR
,
1060 "running invalidator");
1062 while ((head
= heap_head (invalid_heap
)) == NULL
)
1063 LWP_WaitProcess (invalid_heap
);
1065 gettimeofday (&tv
, NULL
);
1067 while ((head
= heap_head (invalid_heap
)) != NULL
) {
1068 FCacheEntry
*entry
= (FCacheEntry
*)head
;
1070 if (tv
.tv_sec
< entry
->callback
.ExpirationTime
) {
1071 unsigned long t
= entry
->callback
.ExpirationTime
- tv
.tv_sec
;
1073 arla_warnx (ADEBINVALIDATOR
,
1074 "invalidator: sleeping for %lu second(s)", t
);
1079 ObtainWriteLock (&entry
->lock
);
1080 if (head
== heap_head (invalid_heap
)) {
1081 heap_remove_head (invalid_heap
);
1082 entry
->invalid_ptr
= -1;
1083 if (entry
->flags
.kernelp
)
1084 break_callback (entry
);
1085 fcache_poller_unref(entry
);
1087 ReleaseWriteLock (&entry
->lock
);
1093 * Add `entry' to the list of entries to invalidate when its time is
1098 add_to_invalidate (FCacheEntry
*e
)
1100 if (e
->invalid_ptr
!= -1)
1101 heap_remove (invalid_heap
, e
->invalid_ptr
);
1102 heap_insert (invalid_heap
, (const void *)e
, &e
->invalid_ptr
);
1103 LWP_NoYieldSignal (invalid_heap
);
1104 IOMGR_Cancel(invalidator_pid
);
1108 * Remove the entry least-recently used and return it locked. Sleep until
1109 * there is an entry.
1112 static FCacheEntry
*
1113 unlink_lru_entry (void)
1115 FCacheEntry
*entry
= NULL
;
1118 if (current_vnodes
== usedvnodes
)
1119 fcache_need_nodes();
1123 assert (!listemptyp (lrulist
));
1124 for (item
= listtail (lrulist
);
1126 item
= listprev (lrulist
, item
)) {
1128 entry
= (FCacheEntry
*)listdata (item
);
1129 if (!entry
->flags
.usedp
1130 && CheckLock(&entry
->lock
) == 0) {
1131 assert_not_flag(entry
,kernelp
);
1132 ObtainWriteLock (&entry
->lock
);
1133 listdel (lrulist
, entry
->lru_le
);
1134 entry
->lru_le
= NULL
;
1139 assert (!listemptyp (lrulist
));
1140 for (item
= listtail (lrulist
);
1142 item
= listprev (lrulist
, item
)) {
1144 entry
= (FCacheEntry
*)listdata (item
);
1145 if (entry
->flags
.usedp
1146 && !entry
->flags
.attrusedp
1147 && !entry
->flags
.kernelp
1148 && entry
->refcount
== 0
1149 && CheckLock(&entry
->lock
) == 0) {
1150 assert_not_flag(entry
,kernelp
);
1151 ObtainWriteLock (&entry
->lock
);
1152 listdel (lrulist
, entry
->lru_le
);
1153 entry
->lru_le
= NULL
;
1154 throw_entry (entry
);
1159 arla_warnx (ADEBFCACHE
, "unlink_lru_entry: sleeping");
1160 fcache_need_nodes();
1165 * Return a usable locked entry.
1168 static FCacheEntry
*
1169 find_free_entry (void)
1173 entry
= unlink_lru_entry ();
1175 arla_warnx (ADEBWARN
, "All vnode entries in use");
1177 AssertExclLocked(&entry
->lock
);
1187 struct fstore_context
{
1193 fcache_store_entry (struct fcache_store
*st
, void *ptr
)
1195 struct fstore_context
*c
;
1198 c
= (struct fstore_context
*)ptr
;
1199 if (c
->item
== NULL
) /* check if done ? */
1202 entry
= (FCacheEntry
*)listdata (c
->item
);
1203 c
->item
= listprev (lrulist
, c
->item
);
1205 if (!entry
->flags
.usedp
)
1208 strlcpy(st
->cell
, cell_num2name(entry
->fid
.Cell
), sizeof(st
->cell
));
1209 st
->fid
= entry
->fid
.fid
;
1210 st
->refcount
= entry
->refcount
;
1211 st
->length
= entry
->length
;
1212 st
->fetched_length
= entry
->fetched_length
;
1213 st
->volsync
= entry
->volsync
;
1214 st
->status
= entry
->status
;
1215 st
->anonaccess
= entry
->anonaccess
;
1216 st
->index
= entry
->index
;
1217 st
->flags
.attrp
= entry
->flags
.attrp
;
1218 st
->flags
.datap
= entry
->length
? TRUE
: FALSE
;
1219 st
->flags
.extradirp
= entry
->flags
.extradirp
;
1220 st
->flags
.mountp
= entry
->flags
.mountp
;
1221 st
->flags
.fake_mp
= entry
->flags
.fake_mp
;
1222 st
->flags
.vol_root
= entry
->flags
.vol_root
;
1223 strlcpy(st
->parentcell
, cell_num2name(entry
->parent
.Cell
),
1224 sizeof(st
->parentcell
));
1225 st
->parent
= entry
->parent
.fid
;
1226 st
->priority
= entry
->priority
;
1237 fcache_store_state (void)
1239 struct fstore_context c
;
1242 if (lrulist
== NULL
) {
1243 arla_warnx (ADEBFCACHE
, "store_state: lrulist is NULL\n");
1247 c
.item
= listtail(lrulist
);
1250 ret
= state_store_fcache("fcache", fcache_store_entry
, &c
);
1252 arla_warn(ADEBWARN
, ret
, "failed to write fcache state");
1254 arla_warnx (ADEBFCACHE
, "wrote %u entries to fcache", c
.n
);
1264 fcache_recover_entry (struct fcache_store
*st
, void *ptr
)
1266 AFSCallBack broken_callback
= {0, 0, CBDROPPED
};
1267 unsigned *n
= (unsigned *)ptr
;
1276 cellid
= cell_name2num(st
->cell
);
1277 assert (cellid
!= -1);
1279 ce
= cred_get (cellid
, 0, 0);
1280 assert (ce
!= NULL
);
1282 res
= volcache_getbyid (st
->fid
.Volume
, cellid
, ce
, &vol
, NULL
);
1288 e
= calloc(1, sizeof(FCacheEntry
));
1289 e
->invalid_ptr
= -1;
1290 Lock_Init(&e
->lock
);
1291 ObtainWriteLock(&e
->lock
);
1294 e
->fid
.Cell
= cellid
;
1295 e
->fid
.fid
= st
->fid
;
1297 e
->status
= st
->status
;
1298 e
->length
= st
->length
;
1299 e
->fetched_length
= st
->fetched_length
;
1300 e
->callback
= broken_callback
;
1301 e
->volsync
= st
->volsync
;
1302 e
->refcount
= st
->refcount
;
1304 /* Better not restore the rights. pags don't have to be the same */
1305 for (i
= 0; i
< NACCESS
; ++i
) {
1306 e
->acccache
[i
].cred
= ARLA_NO_AUTH_CRED
;
1307 e
->acccache
[i
].access
= ANONE
;
1310 e
->anonaccess
= st
->anonaccess
;
1311 e
->index
= st
->index
;
1312 fcache_create_file(e
, 0);
1313 set_recovered(e
->index
);
1314 e
->flags
.usedp
= TRUE
;
1315 e
->flags
.attrp
= st
->flags
.attrp
;
1316 /* st->flags.datap */
1317 e
->flags
.attrusedp
= FALSE
;
1318 e
->flags
.datausedp
= FALSE
;
1319 e
->flags
.kernelp
= FALSE
;
1320 e
->flags
.extradirp
= st
->flags
.extradirp
;
1321 e
->flags
.mountp
= st
->flags
.mountp
;
1322 e
->flags
.fake_mp
= st
->flags
.fake_mp
;
1323 e
->flags
.vol_root
= st
->flags
.vol_root
;
1324 e
->flags
.sentenced
= FALSE
;
1325 e
->flags
.silly
= FALSE
;
1327 e
->parent
.Cell
= cell_name2num(st
->parentcell
);
1328 assert(e
->parent
.Cell
!= -1);
1329 e
->parent
.fid
= st
->parent
;
1330 e
->priority
= st
->priority
;
1333 e
->lru_le
= listaddhead (lrulist
, e
);
1336 hashtabadd (hashtab
, e
);
1338 usedbytes
+= e
->length
;
1339 ReleaseWriteLock (&e
->lock
);
1351 fcache_recover_state (void)
1356 state_recover_fcache("fcache", fcache_recover_entry
, &n
);
1358 arla_warnx (ADEBFCACHE
, "recovered %u entries to fcache", n
);
1363 * Search for `cred' in `ae' and return a pointer in `pos'. If it
1364 * already exists return TRUE, else return FALSE and set pos to a
1369 findaccess (nnpfs_pag_t cred
, AccessEntry
*ae
, AccessEntry
**pos
)
1373 for(i
= 0; i
< NACCESS
; ++i
)
1374 if(ae
[i
].cred
== cred
) {
1379 i
= rand() % NACCESS
;
1390 fs_rtt_cmp (const void *v1
, const void *v2
)
1392 struct fs_server_entry
*e1
= (struct fs_server_entry
*)v1
;
1393 struct fs_server_entry
*e2
= (struct fs_server_entry
*)v2
;
1395 return conn_rtt_cmp(&e1
->conn
, &e2
->conn
);
1399 * Initialize a `fs_server_context'.
1403 init_fs_server_context (fs_server_context
*context
)
1405 context
->num_conns
= 0;
1409 find_partition (fs_server_context
*context
)
1411 int i
= context
->conns
[context
->i
- 1].ve_ent
;
1413 if (i
< 0 || i
>= context
->ve
->entry
.nServers
)
1415 return context
->ve
->entry
.serverPartition
[i
];
1419 * Find the next fileserver for the request in `context'.
1420 * Returns a ConnCacheEntry or NULL.
1424 find_next_fs (fs_server_context
*context
,
1425 ConnCacheEntry
*prev_conn
,
1429 if (host_downp(error
))
1430 conn_dead (prev_conn
);
1431 if (volume_downp(error
))
1432 volcache_mark_down (context
->ve
,
1433 context
->conns
[context
->i
- 1].ve_ent
,
1435 } else if (prev_conn
) {
1436 assert(prev_conn
== context
->conns
[context
->i
- 1].conn
);
1437 volcache_reliable_el(context
->ve
, context
->conns
[context
->i
- 1].ve_ent
);
1440 if (context
->i
< context
->num_conns
)
1441 return context
->conns
[context
->i
++].conn
;
1447 * Clean up a `fs_server_context'
1451 free_fs_server_context (fs_server_context
*context
)
1455 for (i
= 0; i
< context
->num_conns
; ++i
)
1456 conn_free (context
->conns
[i
].conn
);
1459 volcache_process_marks(context
->ve
);
1463 * Find the the file servers housing the volume for `e' and store it
1468 init_fs_context (FCacheEntry
*e
,
1470 fs_server_context
*context
)
1472 VolCacheEntry
*ve
= e
->volume
;
1476 int cell
= e
->fid
.Cell
;
1479 memset(context
, 0, sizeof(*context
));
1482 ret
= volcache_getbyid (e
->fid
.fid
.Volume
, e
->fid
.Cell
,
1483 ce
, &e
->volume
, NULL
);
1489 ret
= volume_make_uptodate (ve
, ce
);
1493 bit
= volcache_volid2bit (ve
, e
->fid
.fid
.Volume
);
1496 /* the volume entry is inconsistent. */
1497 volcache_invalidate_ve (ve
);
1502 for (i
= 0; i
< min(NMAXNSERVERS
,ve
->entry
.nServers
); ++i
) {
1503 u_long addr
= htonl(ve
->entry
.serverNumber
[i
]);
1505 if (ve
->entry
.serverFlags
[i
] & bit
1507 && (ve
->entry
.serverFlags
[i
] & VLSF_DONTUSE
) == 0) {
1508 ConnCacheEntry
*conn
;
1510 conn
= conn_get (cell
, addr
, afsport
,
1511 FS_SERVICE_ID
, fs_probe
, ce
);
1512 if (!conn_isalivep (conn
))
1513 conn
->rtt
= INT_MAX
/2 ;
1514 else if (!volcache_reliablep_el(ve
, i
))
1515 conn
->rtt
= INT_MAX
/4;
1517 conn
->rtt
= rx_PeerOf(conn
->connection
)->srtt
1518 + rand() % RTT_FUZZ
- RTT_FUZZ
/ 2;
1519 context
->conns
[num_clones
].conn
= conn
;
1520 context
->conns
[num_clones
].ve_ent
= i
;
1525 if (num_clones
== 0)
1530 qsort (context
->conns
, num_clones
, sizeof(*context
->conns
),
1533 context
->num_conns
= num_clones
;
1540 * Find the first file server housing the volume for `e'.
1544 find_first_fs (fs_server_context
*context
)
1546 return find_next_fs (context
, NULL
, 0);
1550 * Initialize the file cache in `cachedir', with these values for high
1551 * and low-water marks.
1555 fcache_init (u_long alowvnodes
,
1562 * Initialize all variables.
1566 fhopen_working
= k_hasafs ();
1571 collectstats_init ();
1574 lowvnodes
= alowvnodes
;
1575 highvnodes
= ahighvnodes
;
1576 lowbytes
= alowbytes
;
1577 highbytes
= ahighbytes
;
1579 hashtab
= hashtabnew (FCHASHSIZE
, fcachecmp
, fcachehash
);
1580 if (hashtab
== NULL
)
1581 arla_errx (1, ADEBERROR
, "fcache: hashtabnew failed");
1583 lrulist
= listnew ();
1584 if (lrulist
== NULL
)
1585 arla_errx (1, ADEBERROR
, "fcache: listnew failed");
1587 invalid_heap
= heap_new (ahighvnodes
, expiration_time_cmp
);
1588 if (invalid_heap
== NULL
)
1589 arla_errx (1, ADEBERROR
, "fcache: heap_new failed");
1592 fcache_recover_state ();
1594 if (LWP_CreateProcess (create_nodes
, 0, 1, NULL
, "fcache-create-nodes",
1596 arla_errx (1, ADEBERROR
,
1597 "fcache: cannot create create-nodes thread");
1599 if (LWP_CreateProcess (cleaner
, 0, 1, NULL
, "fcache-cleaner",
1601 arla_errx (1, ADEBERROR
,
1602 "fcache: cannot create cleaner thread");
1604 if (LWP_CreateProcess (invalidator
, 0, 1, NULL
, "fcache-invalidator",
1606 arla_errx (1, ADEBERROR
,
1607 "fcache: cannot create invalidator thread");
1611 * set new values for those of lowvnodes, highvnodes that are not zero.
1612 * do some sanity checks
1613 * return 0 or an error code
1617 fcache_setvnodes(u_long alowvnodes
,
1620 int64_t high
= highvnodes
;
1621 int64_t low
= lowvnodes
;
1623 arla_warnx (ADEBFCACHE
, "fcache_setvnodes");
1625 if (ahighvnodes
!= 0)
1628 if (alowvnodes
!= 0)
1634 if (high
> highvnodes
)
1635 LWP_NoYieldSignal (create_nodes
);
1641 * set new values for those of lowvnodes, highvnodes that are not zero.
1642 * do some sanity checks
1643 * return 0 or an error code
1647 fcache_setbytes(int64_t alowbytes
,
1650 int64_t high
= highbytes
;
1651 int64_t low
= lowbytes
;
1653 arla_warnx (ADEBFCACHE
, "fcache_setbytes");
1658 if (ahighbytes
!= 0)
1671 * set new high/low values for vnodes and bytes.
1672 * return 0 or an error code
1676 fcache_reinit(u_long alowvnodes
,
1681 int error
= fcache_setvnodes(alowvnodes
, ahighvnodes
);
1685 return fcache_setbytes(alowbytes
, ahighbytes
);
1689 * Find the entry for `fid' in the hash table.
1690 * If it's found, move it to the front of `lrulist' as well.
1693 static FCacheEntry
*
1694 find_entry_nolock (VenusFid fid
)
1699 if (hashtab
== NULL
)
1703 e
= (FCacheEntry
*)hashtabsearch (hashtab
, (void *)&key
);
1705 listdel (lrulist
, e
->lru_le
);
1706 e
->lru_le
= listaddhead (lrulist
, e
);
1713 * Mark `e' as having `callback' and notify the kernel.
1714 * This might be overly harsh to opened files.
1718 stale (FCacheEntry
*e
, AFSCallBack callback
)
1720 if (callback
.CallBackType
== CBDROPPED
&&
1721 e
->callback
.CallBackType
== CBDROPPED
)
1724 if (CheckLock (&e
->lock
) != 0)
1725 e
->flags
.sentenced
= TRUE
;
1727 ObtainWriteLock (&e
->lock
);
1728 fcache_poller_unref(e
);
1729 e
->callback
= callback
;
1731 if (e
->flags
.kernelp
)
1735 if (e
->status
.FileType
== TYPE_DIR
&& e
->length
)
1737 ReleaseWriteLock (&e
->lock
);
1743 AFSCallBack callback
;
1747 * Iterate over all entries until we find an entry that matches in
1748 * only fid (without cell) and stale it.
1752 stale_unknown_cell (void *ptr
, void *arg
)
1754 FCacheEntry
*e
= (FCacheEntry
*)ptr
;
1755 struct stale_arg
*sa
= (struct stale_arg
*)arg
;
1757 if (e
->fid
.fid
.Volume
== sa
->fid
.fid
.Volume
1758 && e
->fid
.fid
.Vnode
== sa
->fid
.fid
.Vnode
1759 && e
->fid
.fid
.Unique
== sa
->fid
.fid
.Unique
)
1760 stale (e
, sa
->callback
);
1766 * Call stale on the entry corresponding to `fid', if any.
1770 fcache_stale_entry (VenusFid fid
, AFSCallBack callback
)
1774 if (fid
.Cell
== -1) {
1775 struct stale_arg arg
;
1778 arg
.callback
= callback
;
1780 hashtabforeach (hashtab
, stale_unknown_cell
, &arg
);
1784 e
= find_entry_nolock (fid
);
1786 arla_warnx (ADEBFCACHE
,
1787 "callback for non-existing file (%d, %u, %u, %u)",
1788 fid
.Cell
, fid
.fid
.Volume
, fid
.fid
.Vnode
, fid
.fid
.Unique
);
1791 stale (e
, callback
);
1800 * If ptr has cred arg, set it invalid
1804 purge_cred (void *ptr
, void *arg
)
1806 FCacheEntry
*e
= (FCacheEntry
*)ptr
;
1807 fc_purgecred
*cred
= (fc_purgecred
*) arg
;
1808 AccessEntry
*ae
= e
->acccache
;
1811 if (e
->fid
.Cell
== cred
->cell
|| cred
->cell
== -1) {
1813 for(i
= 0; i
< NACCESS
; ++i
)
1814 if(ae
[i
].cred
== cred
->pag
) {
1815 ae
[i
].cred
= ARLA_NO_AUTH_CRED
;
1816 ae
[i
].access
= ANONE
;
1817 if (e
->flags
.kernelp
)
1818 install_attr (e
, FCACHE2NNPFSNODE_NO_LENGTH
);
1827 * Mark cred as stale in kernel and all fcache-entries,
1828 * When cell == -1, flush all creds in this pag.
1832 fcache_purge_cred (nnpfs_pag_t pag
, int32_t cell
)
1839 hashtabforeach(hashtab
, purge_cred
, &cred
);
1843 * If ptr was retrieved from cell - volume , try to mark stale
1847 purge_volume (void *ptr
, void *arg
)
1849 FCacheEntry
*e
= (FCacheEntry
*)ptr
;
1850 VenusFid
*fid
= (VenusFid
*) arg
;
1851 AFSCallBack broken_callback
= {0, 0, CBDROPPED
};
1853 if ((e
->fid
.Cell
== fid
->Cell
|| fid
->Cell
== -1)
1854 && e
->fid
.fid
.Volume
== fid
->fid
.Volume
) {
1855 stale (e
, broken_callback
);
1861 * Mark all entries from cell.volume as stale
1865 fcache_purge_volume (VenusFid fid
)
1867 hashtabforeach(hashtab
, purge_volume
, &fid
);
1871 * If `ptr' was retrieved from `host', mark it as stale.
1875 purge_host (void *ptr
, void *arg
)
1877 FCacheEntry
*e
= (FCacheEntry
*)ptr
;
1878 u_long
*host
= (u_long
*)arg
;
1879 AFSCallBack broken_callback
= {0, 0, CBDROPPED
};
1882 if (e
->host
== *host
)
1883 stale (e
, broken_callback
);
1888 * Mark all entries from the host `host' as stale.
1892 fcache_purge_host (u_long host
)
1894 hashtabforeach (hashtab
, purge_host
, &host
);
1899 * If `ptr' is a mountpoint, mark it as stale.
1903 invalidate_mp (void *ptr
, void *arg
)
1905 FCacheEntry
*e
= (FCacheEntry
*)ptr
;
1906 AFSCallBack broken_callback
= {0, 0, CBDROPPED
};
1908 if (e
->flags
.mountp
)
1909 stale (e
, broken_callback
);
1914 * Invalidate all mountpoints to force them to be reread.
1918 fcache_invalidate_mp (void)
1920 hashtabforeach (hashtab
, invalidate_mp
, NULL
);
1924 * Mark `entry' as not being used.
1928 fcache_unused (FCacheEntry
*entry
)
1930 AssertExclLocked(&entry
->lock
);
1932 entry
->flags
.datausedp
= entry
->flags
.attrusedp
= FALSE
;
1933 listdel (lrulist
, entry
->lru_le
);
1934 entry
->lru_le
= listaddtail (lrulist
, entry
);
1935 assert (entry
->lru_le
);
1938 * we don't signal lrulist here since we never
1939 * free the node (usedvnode--);
1942 /* if node is deleted from kernel and from fileserver, throw the data */
1943 if (entry
->flags
.silly
&& !entry
->flags
.kernelp
&& entry
->length
)
1948 * make up some status that might be valid for a mount-point
1952 fake_mp_status (FCacheEntry
*e
)
1954 AFSFetchStatus
*status
= &e
->status
;
1956 status
->FileType
= TYPE_DIR
;
1957 status
->LinkCount
= 100;
1958 status
->UnixModeBits
= 0777;
1959 status
->ClientModTime
= 0;
1960 status
->ServerModTime
= 0;
1966 * Return true if `entry' is a mountpoint
1970 mountpointp (FCacheEntry
*entry
)
1972 if (entry
->status
.FileType
== TYPE_LINK
1973 && fcache_get_status_length(&entry
->status
) != 0
1974 && entry
->status
.UnixModeBits
== 0644)
1980 * Mark `entry' as mountpoint or a fake mountpoint depending on
1981 * fake_mp is used or not.
1985 fcache_mark_as_mountpoint (FCacheEntry
*entry
)
1988 entry
->flags
.fake_mp
= TRUE
;
1989 fake_mp_status (entry
);
1991 entry
->flags
.mountp
= TRUE
;
1996 * Update all the relevant parts of `entry' after having received new
1997 * data from the file server.
2001 update_entry (FCacheEntry
*entry
,
2002 AFSFetchStatus
*status
,
2003 AFSCallBack
*callback
,
2004 AFSVolSync
*volsync
,
2005 ConnCacheEntry
*conn
,
2010 unsigned long bitmask
= 0141777; /* REG, DIR, STICKY, USR, GRP, OTH */
2012 if (entry
->volume
&& cell_issuid_by_num (entry
->volume
->cell
))
2013 bitmask
|= 0006000; /* SUID, SGID */
2015 gettimeofday (&tv
, NULL
);
2017 entry
->status
= *status
;
2018 entry
->status
.UnixModeBits
&= bitmask
;
2020 entry
->callback
= *callback
;
2021 entry
->callback
.ExpirationTime
+= tv
.tv_sec
;
2022 add_to_invalidate (entry
);
2025 entry
->volsync
= *volsync
;
2027 volcache_update_volsync (entry
->volume
, *volsync
);
2031 fcache_poller_reref(entry
, conn
);
2032 entry
->host
= rx_HostOf(rx_PeerOf(conn
->connection
));
2034 fcache_poller_unref(entry
);
2038 entry
->anonaccess
= status
->AnonymousAccess
;
2039 findaccess (cred
, entry
->acccache
, &ae
);
2041 ae
->access
= status
->CallerAccess
;
2042 if (!entry
->flags
.mountp
&& mountpointp (entry
))
2043 fcache_mark_as_mountpoint (entry
);
2047 * Update entry, common code for do_read_attr and get_attr_bulk
2051 update_attr_entry (FCacheEntry
*entry
,
2052 AFSFetchStatus
*status
,
2053 AFSCallBack
*callback
,
2054 AFSVolSync
*volsync
,
2055 ConnCacheEntry
*conn
,
2058 if (entry
->fetched_length
2059 && entry
->status
.DataVersion
!= status
->DataVersion
2060 && !entry
->flags
.datausedp
)
2063 entry
->tokens
&= ~(NNPFS_DATA_R
|NNPFS_DATA_W
);
2066 update_entry (entry
, status
, callback
, volsync
,
2069 entry
->tokens
|= NNPFS_ATTR_R
;
2070 entry
->flags
.attrp
= TRUE
;
2075 * Give up all callbacks.
2079 giveup_all_callbacks (uint32_t cell
, uint32_t host
, void *arg
)
2082 ConnCacheEntry
*conn
;
2085 ce
= cred_get (cell
, 0, CRED_ANY
);
2086 assert (ce
!= NULL
);
2088 conn
= conn_get (cell
, host
, afsport
, FS_SERVICE_ID
, fs_probe
, ce
);
2091 if (conn_isalivep (conn
)) {
2093 ret
= RXAFS_GiveUpAllCallBacks(conn
->connection
);
2094 if (ret
!= 0 && ret
!= RXGEN_OPCODE
) {
2095 struct in_addr in_addr
;
2097 in_addr
.s_addr
= rx_HostOf(rx_PeerOf(conn
->connection
));
2098 arla_warn (ADEBWARN
, ret
, "GiveUpAllCallBacks %s",
2099 inet_ntoa (in_addr
));
2100 if (host_downp(ret
)) {
2113 fcache_giveup_all_callbacks (void)
2117 poller_foreach(giveup_all_callbacks
, NULL
);
2119 for (item
= listtail(lrulist
);
2121 item
= listprev(lrulist
, item
)) {
2122 FCacheEntry
*entry
= (FCacheEntry
*)listdata(item
);
2124 if (entry
->flags
.attrp
&&
2125 entry
->flags
.silly
== FALSE
&&
2129 ConnCacheEntry
*conn
;
2134 ce
= cred_get (entry
->fid
.Cell
, 0, CRED_ANY
);
2135 assert (ce
!= NULL
);
2137 conn
= conn_get (entry
->fid
.Cell
, entry
->host
, afsport
,
2138 FS_SERVICE_ID
, fs_probe
, ce
);
2141 fids
.len
= cbs
.len
= 1;
2142 fids
.val
= &entry
->fid
.fid
;
2143 cbs
.val
= &entry
->callback
;
2145 if (conn_isalivep (conn
)) {
2146 ret
= RXAFS_GiveUpCallBacks (conn
->connection
, &fids
, &cbs
);
2148 struct in_addr in_addr
;
2150 in_addr
.s_addr
= rx_HostOf(rx_PeerOf(conn
->connection
));
2151 arla_warn (ADEBFCACHE
, ret
, "RXAFS_GiveUpCallBacks %s",
2152 inet_ntoa (in_addr
));
2162 * discard all cached attrs to force revalidation of entries
2163 * intended for reconnect after disconnected mode.
2167 fcache_discard_attrs(void)
2171 for (item
= listtail(lrulist
);
2173 item
= listprev(lrulist
, item
)) {
2174 FCacheEntry
*entry
= (FCacheEntry
*)listdata(item
);
2176 if (entry
->flags
.attrp
&&
2177 entry
->flags
.silly
== FALSE
)
2178 entry
->flags
.attrp
= FALSE
;
2183 * Obtain new callbacks for all entries in the cache.
2187 fcache_reobtain_callbacks (struct nnpfs_cred
*cred
)
2192 for (item
= listtail(lrulist
);
2194 item
= listprev(lrulist
, item
)) {
2195 FCacheEntry
*entry
= (FCacheEntry
*)listdata(item
);
2197 ObtainWriteLock (&entry
->lock
);
2198 if (entry
->flags
.usedp
&&
2199 entry
->flags
.silly
== FALSE
&&
2203 ConnCacheEntry
*conn
;
2204 AFSFetchStatus status
;
2205 AFSCallBack callback
;
2209 ce
= cred_get (entry
->fid
.Cell
, cred
->pag
, CRED_ANY
);
2210 assert (ce
!= NULL
);
2212 conn
= conn_get (entry
->fid
.Cell
, entry
->host
, afsport
,
2213 FS_SERVICE_ID
, fs_probe
, ce
);
2214 if (!conn_isalivep(conn
))
2217 * does this belong here?
2220 ret
= volcache_getbyid (entry
->fid
.fid
.Volume
,
2221 entry
->fid
.Cell
, ce
, &vol
, NULL
);
2223 entry
->volume
= vol
;
2225 ret
= RXAFS_FetchStatus (conn
->connection
,
2231 arla_warn (ADEBFCACHE
, ret
, "RXAFS_FetchStatus");
2233 update_attr_entry (entry
, &status
, &callback
, &volsync
,
2235 if (entry
->flags
.kernelp
)
2236 break_callback (entry
);
2238 fcache_counter
.fetch_attr
++;
2244 ReleaseWriteLock (&entry
->lock
);
2250 * Return true iff there's any point in trying the next fs.
2254 try_next_fs (int error
, const VenusFid
*fid
)
2258 case RXKADUNKNOWNKEY
:
2260 case ARLA_CALL_DEAD
:
2261 case ARLA_INVALID_OPERATION
:
2262 case ARLA_CALL_TIMEOUT
:
2264 case ARLA_PROTOCOL_ERROR
:
2265 case ARLA_USER_ABORT
:
2266 case ARLA_ADDRINUSE
:
2268 case ARLA_VSALVAGE
:
2269 case ARLA_VNOSERVICE
:
2270 case ARLA_VOFFLINE
:
2276 if (fid
&& !volcache_reliablep (fid
->fid
.Volume
, fid
->Cell
))
2277 volcache_invalidate (fid
->fid
.Volume
, fid
->Cell
);
2287 * If the whole file is fetched as we last saw it, lets write down
2288 * the whole file to the fileserver. If the file is shrinking,
2289 * make sure we don't cache non-existing bytes.
2293 new_fetched_length(FCacheEntry
*entry
, uint64_t cache_file_size
)
2297 AssertExclLocked(&entry
->lock
);
2299 if (entry
->fetched_length
== fcache_get_status_length(&entry
->status
))
2300 have_len
= cache_file_size
;
2302 have_len
= entry
->fetched_length
;
2303 /* have file shrinked ? */
2304 if (have_len
> cache_file_size
)
2305 have_len
= cache_file_size
;
2312 * Fetch the attributes for the file in `entry' from the file_server,
2313 * using the credentials in `ce' and returning the connection in
2316 * `entry' must be write-locked.
2318 * If an error code is returned `fs_server_context' is already freed.
2319 * If everything is ok, `fs_server_context' must be freed by the caller.
2323 do_read_attr (FCacheEntry
*entry
,
2325 ConnCacheEntry
**ret_conn
,
2326 fs_server_context
*ret_context
)
2328 ConnCacheEntry
*conn
;
2329 AFSFetchStatus status
;
2330 AFSCallBack callback
;
2332 struct collect_stat collectstat
;
2335 AssertExclLocked(&entry
->lock
);
2339 ret
= init_fs_context(entry
, ce
, ret_context
);
2343 for (conn
= find_first_fs (ret_context
);
2345 conn
= find_next_fs (ret_context
, conn
, ret
)) {
2347 collectstats_start(&collectstat
);
2348 ret
= RXAFS_FetchStatus (conn
->connection
,
2353 collectstats_stop(&collectstat
, entry
, conn
,
2354 find_partition(ret_context
),
2355 arla_STATISTICS_REQTYPE_FETCHSTATUS
, 1);
2356 arla_warnx (ADEBFCACHE
, "trying to fetch status: %d", ret
);
2357 if (!try_next_fs (ret
, &entry
->fid
))
2361 arla_warn (ADEBFCACHE
, ret
, "fetch-status");
2362 if (host_downp(ret
))
2364 free_fs_server_context (ret_context
);
2368 fcache_counter
.fetch_attr
++;
2370 update_attr_entry (entry
, &status
, &callback
, &volsync
,
2373 AssertExclLocked(&entry
->lock
);
2381 * Read the attributes of `entry' from the file server and store them.
2382 * `e' must be write-locked.
2386 read_attr (FCacheEntry
*entry
, CredCacheEntry
*ce
)
2389 ConnCacheEntry
*conn
;
2390 fs_server_context context
;
2392 AssertExclLocked(&entry
->lock
);
2394 init_fs_server_context (&context
);
2395 ret
= do_read_attr (entry
, ce
, &conn
, &context
);
2398 free_fs_server_context (&context
);
2403 * Read the contents of `entry' from the file server and store it.
2407 read_data (FCacheEntry
*entry
, ConnCacheEntry
*conn
, CredCacheEntry
*ce
,
2410 struct rx_call
*call
;
2412 uint64_t wanted_length
, nbytes
= 0;
2416 AFSFetchStatus status
;
2417 AFSCallBack callback
;
2419 struct collect_stat collectstat
;
2422 arla_warnx (ADEBMISC
, "read_data");
2424 AssertExclLocked(&entry
->lock
);
2426 if (connected_mode
== DISCONNECTED
) {
2431 /* are we already done ? */
2432 if (entry
->wanted_length
<= entry
->fetched_length
) {
2437 /* figure out how much more then we need we want to fetch */
2438 wanted_length
= stats_fetch_round(conn
, partition
, entry
->wanted_length
);
2439 if (wanted_length
> fcache_get_status_length(&entry
->status
))
2440 wanted_length
= fcache_get_status_length(&entry
->status
);
2442 /* we need more space ? */
2443 if (wanted_length
> entry
->length
)
2444 nbytes
= wanted_length
- entry
->length
;
2446 if (usedbytes
+ nbytes
> highbytes
) {
2447 ret
= fcache_need_bytes (nbytes
);
2452 if (usedbytes
+ nbytes
> highbytes
) {
2453 arla_warnx (ADEBWARN
, "Out of space, not enough cache "
2454 "(file-length: %lu need bytes: %ld usedbytes: %ld)",
2455 (unsigned long)fcache_get_status_length(&entry
->status
),
2456 (long)nbytes
, (long)usedbytes
);
2462 /* now go talk to the world */
2463 call
= rx_NewCall (conn
->connection
);
2465 arla_warnx (ADEBMISC
, "rx_NewCall failed");
2470 collectstats_start(&collectstat
);
2471 if (conn_get_fs_support64(conn
)) {
2472 ret
= StartRXAFS_FetchData64 (call
,
2474 entry
->fetched_length
,
2475 wanted_length
- entry
->fetched_length
);
2476 if (ret
== RXGEN_OPCODE
) {
2477 rx_EndCall(call
,ret
);
2478 conn_set_fs_support64(conn
, FALSE
);
2481 } else if (entry
->fetched_length
>> 32)
2484 ret
= StartRXAFS_FetchData (call
,
2486 entry
->fetched_length
,
2487 wanted_length
- entry
->fetched_length
);
2490 arla_warn (ADEBFCACHE
, ret
, "fetch-data");
2491 rx_EndCall(call
,ret
);
2495 if (conn_get_fs_support64(conn
)) {
2496 ret
= rx_Read (call
, &sizefs4
, sizeof(sizefs4
));
2497 if (ret
!= sizeof(sizefs4
)) {
2498 ret
= rx_GetCallError(call
);
2499 if (ret
== RXGEN_OPCODE
&& conn_get_fs_support64(conn
)) {
2501 conn_set_fs_support64(conn
, FALSE
);
2504 ret
= conv_to_arla_errno(ret
);
2505 arla_warn (ADEBFCACHE
, ret
, "Error reading length");
2506 rx_EndCall(call
, 0);
2509 sizefs
= (uint64_t)ntohl(sizefs4
) << 32;
2512 ret
= rx_Read (call
, &sizefs4
, sizeof(sizefs4
));
2513 if (ret
!= sizeof(sizefs4
)) {
2514 ret
= conv_to_arla_errno(rx_GetCallError(call
));
2515 arla_warn (ADEBFCACHE
, ret
, "Error reading length");
2516 rx_EndCall(call
, 0);
2519 sizefs
|= ntohl (sizefs4
);
2523 fd
= fcache_open_file (entry
, O_RDWR
);
2526 arla_warn (ADEBFCACHE
, ret
, "open cache file %u",
2527 (unsigned)entry
->index
);
2528 rx_EndCall(call
, 0);
2532 if (ftruncate(fd
, fcache_get_status_length(&entry
->status
)) < 0) {
2535 rx_EndCall(call
, 0);
2539 ret
= copyrx2fd (call
, fd
, entry
->fetched_length
, sizefs
);
2542 arla_warn (ADEBFCACHE
, ret
, "copyrx2fd");
2543 rx_EndCall(call
, ret
);
2547 if (conn_get_fs_support64(conn
)) {
2548 ret
= EndRXAFS_FetchData64 (call
,
2553 ret
= EndRXAFS_FetchData (call
,
2559 arla_warn (ADEBWARN
, ret
, "EndRXAFS_FetchData");
2560 ret
= rx_EndCall (call
, ret
);
2562 arla_warn (ADEBFCACHE
, ret
, "rx_EndCall");
2565 collectstats_stop(&collectstat
, entry
, conn
,
2566 partition
, arla_STATISTICS_REQTYPE_FETCHDATA
, sizefs
);
2568 entry
->fetched_length
+= sizefs
;
2569 sizediff
= entry
->fetched_length
- entry
->length
;
2570 entry
->length
= entry
->fetched_length
;
2571 usedbytes
+= sizediff
;
2573 fcache_counter
.fetch_data
++;
2575 update_entry (entry
, &status
, &callback
, &volsync
,
2578 entry
->tokens
|= NNPFS_DATA_R
;
2581 AssertExclLocked(&entry
->lock
);
2587 * Write the contents of the cache file back to the file server.
2589 * If data_entry is not null, use that as data source.
2593 write_data (FCacheEntry
*entry
, FCacheEntry
*data_entry
,
2594 AFSStoreStatus
*storestatus
, CredCacheEntry
*ce
)
2596 FCacheEntry
*fd_entry
= entry
;
2597 ConnCacheEntry
*conn
;
2598 struct rx_call
*call
;
2602 uint64_t status_len
;
2604 struct stat statinfo
;
2605 AFSFetchStatus status
;
2607 fs_server_context context
;
2608 struct collect_stat collectstat
;
2610 AssertExclLocked(&entry
->lock
);
2613 AssertExclLocked(&data_entry
->lock
);
2614 fd_entry
= data_entry
;
2616 fd
= fcache_open_file (fd_entry
, O_RDONLY
);
2619 arla_warn (ADEBFCACHE
, ret
, "open cache file %u",
2620 (unsigned)fd_entry
->index
);
2624 if (fstat (fd
, &statinfo
) < 0) {
2627 arla_warn (ADEBFCACHE
, ret
, "stat cache file %u",
2628 (unsigned)fd_entry
->index
);
2631 sizefs
= statinfo
.st_size
;
2633 have_len
= new_fetched_length(fd_entry
, sizefs
);
2635 if (fcache_get_status_length(&entry
->status
) < have_len
)
2636 fcache_set_status_length(&entry
->status
, have_len
);
2637 fcache_update_length (entry
, have_len
, have_len
);
2639 status_len
= fcache_get_status_length(&fd_entry
->status
);
2641 if (connected_mode
!= CONNECTED
|| entry
->flags
.silly
) {
2646 ret
= init_fs_context(entry
, ce
, &context
);
2650 for (conn
= find_first_fs (&context
);
2652 conn
= find_next_fs (&context
, conn
, ret
)) {
2655 call
= rx_NewCall (conn
->connection
);
2657 arla_warnx (ADEBMISC
, "rx_NewCall failed");
2662 collectstats_start(&collectstat
);
2663 if (conn_get_fs_support64(conn
)) {
2664 ret
= StartRXAFS_StoreData64 (call
, &entry
->fid
.fid
,
2669 if (ret
== RXGEN_OPCODE
) {
2670 rx_EndCall(call
,ret
);
2671 conn_set_fs_support64(conn
, FALSE
);
2674 } else if ((uint64_t)have_len
>> 32) {
2677 ret
= StartRXAFS_StoreData (call
, &entry
->fid
.fid
,
2683 if (host_downp(ret
)) {
2684 rx_EndCall(call
, ret
);
2687 arla_warn (ADEBFCACHE
, ret
, "store-data");
2688 rx_EndCall(call
, 0);
2692 ret
= copyfd2rx (fd
, call
, 0, have_len
);
2693 if (ret
== RXGEN_OPCODE
&& conn_get_fs_support64(conn
)) {
2694 rx_EndCall(call
,ret
);
2695 conn_set_fs_support64(conn
, FALSE
);
2698 rx_EndCall(call
, ret
);
2699 arla_warn (ADEBFCACHE
, ret
, "copyfd2rx");
2703 if (conn_get_fs_support64(conn
)) {
2704 ret
= EndRXAFS_StoreData64 (call
,
2707 if (ret
== RXGEN_OPCODE
) {
2708 rx_EndCall(call
, 0);
2709 conn_set_fs_support64(conn
, FALSE
);
2713 ret
= EndRXAFS_StoreData (call
,
2718 rx_EndCall (call
, ret
);
2719 arla_warnx (ADEBFCACHE
, "EndRXAFS_StoreData");
2723 ret
= rx_EndCall (call
, 0);
2725 arla_warn (ADEBFCACHE
, ret
, "rx_EndCall");
2727 collectstats_stop(&collectstat
, entry
, conn
,
2728 find_partition(&context
),
2729 arla_STATISTICS_REQTYPE_STOREDATA
, sizefs
);
2735 fcache_counter
.store_data
++;
2736 update_entry (entry
, &status
, NULL
, &volsync
,
2741 * We can't do this, it will corrupt the cache since nnpfs
2742 * will still think it have the data, and then when we
2743 * write back the file to the fileserver, it will be
2744 * filled with zeros. Happens if you are unlucky so store
2745 * a file at the same moment as your credentials expire.
2748 usedbytes
-= entry
->length
;
2750 entry
->wanted_length
= 0;
2751 entry
->fetched_length
= 0;
2755 if (host_downp(ret
))
2757 free_fs_server_context (&context
);
2758 AssertExclLocked(&entry
->lock
);
2760 AssertExclLocked(&data_entry
->lock
);
2766 * Truncate the file in `entry' to `size' bytes.
2770 truncate_file (FCacheEntry
*entry
, uint64_t size
,
2771 AFSStoreStatus
*storestatus
, CredCacheEntry
*ce
)
2773 fs_server_context context
;
2774 ConnCacheEntry
*conn
;
2775 struct rx_call
*call
;
2776 AFSFetchStatus status
;
2781 AssertExclLocked(&entry
->lock
);
2783 if (connected_mode
!= CONNECTED
)
2786 have_len
= new_fetched_length(entry
, size
);
2788 ret
= init_fs_context(entry
, ce
, &context
);
2792 for (conn
= find_first_fs (&context
);
2794 conn
= find_next_fs (&context
, conn
, ret
)) {
2797 call
= rx_NewCall (conn
->connection
);
2799 arla_warnx (ADEBMISC
, "rx_NewCall failed");
2804 if (conn_get_fs_support64(conn
)) {
2805 ret
= StartRXAFS_StoreData64 (call
,
2811 if (ret
== RXGEN_OPCODE
) {
2812 rx_EndCall(call
, ret
);
2813 conn_set_fs_support64(conn
, FALSE
);
2816 } else if (size
>> 32)
2819 ret
= StartRXAFS_StoreData (call
,
2825 if (host_downp(ret
)) {
2826 rx_EndCall(call
, ret
);
2829 arla_warn (ADEBFCACHE
, ret
, "store-data");
2830 rx_EndCall(call
, 0);
2834 if (conn_get_fs_support64(conn
)) {
2835 ret
= EndRXAFS_StoreData64 (call
,
2838 if (ret
== RXGEN_OPCODE
) {
2839 rx_EndCall(call
, 0);
2840 conn_set_fs_support64(conn
, FALSE
);
2844 ret
= EndRXAFS_StoreData (call
,
2849 rx_EndCall (call
, ret
);
2850 arla_warnx (ADEBFCACHE
, "EndRXAFS_StoreData");
2854 ret
= rx_EndCall (call
, 0);
2856 arla_warn (ADEBFCACHE
, ret
, "rx_EndCall");
2864 fd
= fcache_open_file (entry
, O_RDWR
);
2867 arla_warn (ADEBFCACHE
, ret
, "open fache file %u",
2868 (unsigned)entry
->index
);
2869 free_fs_server_context(&context
);
2873 if(ftruncate (fd
, size
) < 0) {
2875 arla_warn (ADEBFCACHE
, ret
, "ftruncate %ld", (long)size
);
2877 free_fs_server_context(&context
);
2883 fcache_update_length (entry
, size
, have_len
);
2885 fcache_counter
.store_data
++;
2886 update_entry (entry
, &status
, NULL
, &volsync
,
2890 free_fs_server_context (&context
);
2892 if (host_downp(ret
))
2895 AssertExclLocked(&entry
->lock
);
2900 * Set the attributes of the file in `entry' to `status'.
2904 write_attr (FCacheEntry
*entry
,
2905 const AFSStoreStatus
*store_status
,
2908 ConnCacheEntry
*conn
= NULL
;
2910 AFSFetchStatus status
;
2913 AssertExclLocked(&entry
->lock
);
2915 /* Don't write attributes to deleted files */
2916 if (entry
->flags
.silly
)
2919 if (connected_mode
== CONNECTED
) {
2920 fs_server_context context
;
2921 struct collect_stat collectstat
;
2923 ret
= init_fs_context(entry
, ce
, &context
);
2927 for (conn
= find_first_fs (&context
);
2929 conn
= find_next_fs (&context
, conn
, ret
)) {
2931 collectstats_start(&collectstat
);
2932 ret
= RXAFS_StoreStatus (conn
->connection
,
2937 if (host_downp(ret
)) {
2940 arla_warn (ADEBFCACHE
, ret
, "store-status");
2941 free_fs_server_context (&context
);
2950 collectstats_stop(&collectstat
, entry
, conn
,
2951 find_partition(&context
),
2952 arla_STATISTICS_REQTYPE_STORESTATUS
, 1);
2955 free_fs_server_context (&context
);
2957 if (host_downp(ret
)) {
2961 update_entry (entry
, &status
, NULL
, &volsync
, conn
, ce
->cred
);
2964 assert (conn
== NULL
);
2966 fcache_counter
.store_attr
++;
2967 if (store_status
->Mask
& SS_MODTIME
) {
2968 entry
->status
.ClientModTime
= store_status
->ClientModTime
;
2969 entry
->status
.ServerModTime
= store_status
->ClientModTime
;
2971 if (store_status
->Mask
& SS_OWNER
)
2972 entry
->status
.Owner
= store_status
->Owner
;
2973 if (store_status
->Mask
& SS_GROUP
)
2974 entry
->status
.Group
= store_status
->Group
;
2975 if (store_status
->Mask
& SS_MODEBITS
)
2976 entry
->status
.UnixModeBits
= store_status
->UnixModeBits
;
2983 AssertExclLocked(&entry
->lock
);
2993 create_file (FCacheEntry
*dir_entry
,
2994 const char *name
, AFSStoreStatus
*store_attr
,
2995 VenusFid
*child_fid
, AFSFetchStatus
*fetch_attr
,
2998 ConnCacheEntry
*conn
= NULL
;
3001 FCacheEntry
*child_entry
;
3002 AFSFetchStatus status
;
3003 AFSCallBack callback
;
3007 AssertExclLocked(&dir_entry
->lock
);
3009 if (connected_mode
== CONNECTED
) {
3010 fs_server_context context
;
3012 ret
= init_fs_context(dir_entry
, ce
, &context
);
3016 for (conn
= find_first_fs (&context
);
3018 conn
= find_next_fs (&context
, conn
, ret
)) {
3020 ret
= RXAFS_CreateFile (conn
->connection
,
3021 &dir_entry
->fid
.fid
,
3029 if (host_downp(ret
)) {
3032 free_fs_server_context (&context
);
3033 arla_warn (ADEBFCACHE
, ret
, "CreateFile");
3041 free_fs_server_context (&context
);
3043 if (host_downp(ret
)) {
3048 fetch_attr
->CallerAccess
|= AADMIN
;
3050 update_entry (dir_entry
, &status
, &callback
, &volsync
,
3054 static int fakefid
= 1001;
3056 assert(conn
== NULL
);
3060 OutFid
.Volume
= dir_entry
->fid
.fid
.Volume
;
3061 OutFid
.Vnode
= fakefid
;
3062 OutFid
.Unique
= fakefid
;
3065 fetch_attr
->InterfaceVersion
= 1;
3066 fetch_attr
->FileType
= TYPE_FILE
;
3067 fetch_attr
->LinkCount
= 1;
3068 fetch_attr
->Length
= 0;
3069 fetch_attr
->DataVersion
= 1;
3070 fetch_attr
->Author
= store_attr
->Owner
;
3071 fetch_attr
->Owner
= store_attr
->Owner
;
3072 fetch_attr
->CallerAccess
= dir_entry
->status
.CallerAccess
;
3073 fetch_attr
->AnonymousAccess
= dir_entry
->status
.AnonymousAccess
;
3074 fetch_attr
->UnixModeBits
= store_attr
->UnixModeBits
;
3075 fetch_attr
->ParentVnode
= dir_entry
->fid
.fid
.Vnode
;
3076 fetch_attr
->ParentUnique
= dir_entry
->fid
.fid
.Unique
;
3077 fetch_attr
->ResidencyMask
= 1;
3078 fetch_attr
->ClientModTime
= store_attr
->ClientModTime
;
3079 fetch_attr
->ServerModTime
= store_attr
->ClientModTime
;
3080 fetch_attr
->Group
= store_attr
->Group
;
3081 fetch_attr
->SyncCounter
= 0;
3082 fetch_attr
->DataVersionHigh
= 0;
3083 fetch_attr
->LockCount
= 0;
3084 fetch_attr
->LengthHigh
= 0;
3085 fetch_attr
->ErrorCode
= 0;
3088 child_fid
->Cell
= dir_entry
->fid
.Cell
;
3089 child_fid
->fid
= OutFid
;
3091 ret
= fcache_get (&child_entry
, *child_fid
, ce
);
3093 arla_warn (ADEBFCACHE
, ret
, "fcache_get");
3097 update_entry (child_entry
, fetch_attr
, NULL
, NULL
,
3100 child_entry
->flags
.attrp
= TRUE
;
3102 fd
= fcache_open_file (child_entry
, O_WRONLY
);
3105 arla_warn (ADEBFCACHE
, ret
, "open cache file %u",
3106 (unsigned)child_entry
->index
);
3107 fcache_release(child_entry
);
3110 if (ftruncate (fd
, 0) < 0) {
3112 arla_warn (ADEBFCACHE
, ret
, "ftruncate cache file %u",
3113 (unsigned)child_entry
->index
);
3115 fcache_release(child_entry
);
3119 child_entry
->length
= 0;
3121 child_entry
->tokens
|= NNPFS_ATTR_R
| NNPFS_DATA_R
| NNPFS_DATA_W
;
3123 fcache_release(child_entry
);
3129 AssertExclLocked(&dir_entry
->lock
);
3135 * Create a directory.
3139 create_directory (FCacheEntry
*dir_entry
,
3140 const char *name
, AFSStoreStatus
*store_attr
,
3141 VenusFid
*child_fid
, AFSFetchStatus
*fetch_attr
,
3144 ConnCacheEntry
*conn
= NULL
;
3147 FCacheEntry
*child_entry
;
3148 AFSFetchStatus status
;
3149 AFSCallBack callback
;
3153 AssertExclLocked(&dir_entry
->lock
);
3155 if (connected_mode
== CONNECTED
) {
3156 fs_server_context context
;
3158 ret
= init_fs_context(dir_entry
, ce
, &context
);
3162 for (conn
= find_first_fs (&context
);
3164 conn
= find_next_fs (&context
, conn
, ret
)) {
3166 ret
= RXAFS_MakeDir (conn
->connection
,
3167 &dir_entry
->fid
.fid
,
3176 if (host_downp(ret
)) {
3179 free_fs_server_context (&context
);
3180 arla_warn (ADEBFCACHE
, ret
, "MakeDir");
3187 free_fs_server_context (&context
);
3189 if (host_downp(ret
)) {
3194 update_entry (dir_entry
, &status
, &callback
, &volsync
,
3197 static int fakedir
= 1000;
3201 assert(conn
== NULL
);
3203 OutFid
.Volume
= dir_entry
->fid
.fid
.Volume
;
3204 OutFid
.Vnode
= fakedir
;
3205 OutFid
.Unique
= fakedir
;
3208 fetch_attr
->InterfaceVersion
= 1;
3209 fetch_attr
->FileType
= TYPE_DIR
;
3210 fetch_attr
->LinkCount
= 2;
3211 fetch_attr
->Length
= AFSDIR_PAGESIZE
;
3212 fetch_attr
->DataVersion
= 1;
3213 fetch_attr
->Author
= store_attr
->Owner
;
3214 fetch_attr
->Owner
= store_attr
->Owner
;
3215 fetch_attr
->CallerAccess
= dir_entry
->status
.CallerAccess
;
3216 fetch_attr
->AnonymousAccess
= dir_entry
->status
.AnonymousAccess
;
3217 fetch_attr
->UnixModeBits
= store_attr
->UnixModeBits
;
3218 fetch_attr
->ParentVnode
= dir_entry
->fid
.fid
.Vnode
;
3219 fetch_attr
->ParentUnique
= dir_entry
->fid
.fid
.Unique
;
3220 fetch_attr
->ResidencyMask
= 1;
3221 fetch_attr
->ClientModTime
= store_attr
->ClientModTime
;
3222 fetch_attr
->ServerModTime
= store_attr
->ClientModTime
;
3223 fetch_attr
->Group
= store_attr
->Group
;
3224 fetch_attr
->SyncCounter
= 0;
3225 fetch_attr
->DataVersionHigh
= 0;
3226 fetch_attr
->LockCount
= 0;
3227 fetch_attr
->LengthHigh
= 0;
3228 fetch_attr
->ErrorCode
= 0;
3231 child_fid
->Cell
= dir_entry
->fid
.Cell
;
3232 child_fid
->fid
= OutFid
;
3234 ret
= fcache_get (&child_entry
, *child_fid
, ce
);
3236 arla_warn (ADEBFCACHE
, ret
, "fcache_get");
3240 assert(child_entry
->length
== 0);
3242 update_entry (child_entry
, fetch_attr
, NULL
, NULL
,
3245 child_entry
->flags
.attrp
= TRUE
;
3247 ret
= adir_mkdir (child_entry
, child_fid
->fid
, dir_entry
->fid
.fid
);
3249 arla_warn (ADEBFCACHE
, ret
, "adir_mkdir");
3250 fcache_release(child_entry
);
3254 child_entry
->tokens
|= NNPFS_ATTR_R
| NNPFS_DATA_R
| NNPFS_DATA_W
;
3256 fcache_release(child_entry
);
3261 AssertExclLocked(&dir_entry
->lock
);
3266 * Create a symbolic link.
3268 * Note: create_symlink->flags.kernelp is not set on success
3269 * and that must be done by the caller.
3273 create_symlink (FCacheEntry
*dir_entry
,
3274 const char *name
, AFSStoreStatus
*store_attr
,
3275 VenusFid
*child_fid
, AFSFetchStatus
*fetch_attr
,
3276 const char *contents
,
3280 ConnCacheEntry
*conn
;
3282 FCacheEntry
*child_entry
;
3284 AFSFetchStatus new_status
;
3285 fs_server_context context
;
3287 AssertExclLocked(&dir_entry
->lock
);
3289 if (connected_mode
!= CONNECTED
)
3292 ret
= init_fs_context(dir_entry
, ce
, &context
);
3296 for (conn
= find_first_fs (&context
);
3298 conn
= find_next_fs (&context
, conn
, ret
)) {
3300 ret
= RXAFS_Symlink (conn
->connection
,
3301 &dir_entry
->fid
.fid
,
3309 if (host_downp(ret
)) {
3312 arla_warn (ADEBFCACHE
, ret
, "Symlink");
3313 free_fs_server_context (&context
);
3320 free_fs_server_context (&context
);
3322 if (host_downp(ret
)) {
3327 update_entry (dir_entry
, &new_status
, NULL
, &volsync
,
3330 child_fid
->Cell
= dir_entry
->fid
.Cell
;
3331 child_fid
->fid
= OutFid
;
3333 ret
= fcache_get (&child_entry
, *child_fid
, ce
);
3335 arla_warn (ADEBFCACHE
, ret
, "fcache_get");
3339 update_entry (child_entry
, fetch_attr
, NULL
, NULL
,
3343 * flags.kernelp is set in cm_symlink since the symlink
3344 * might be a mountpoint and this entry is never install
3348 child_entry
->flags
.attrp
= TRUE
;
3349 child_entry
->tokens
|= NNPFS_ATTR_R
;
3351 fcache_release(child_entry
);
3356 AssertExclLocked(&dir_entry
->lock
);
3361 * Create a hard link.
3365 create_link (FCacheEntry
*dir_entry
,
3367 FCacheEntry
*existing_entry
,
3370 ConnCacheEntry
*conn
= NULL
;
3372 AFSFetchStatus new_status
;
3373 AFSFetchStatus status
;
3375 fs_server_context context
;
3377 AssertExclLocked(&dir_entry
->lock
);
3379 if (connected_mode
!= CONNECTED
)
3382 ret
= init_fs_context(dir_entry
, ce
, &context
);
3386 for (conn
= find_first_fs (&context
);
3388 conn
= find_next_fs (&context
, conn
, ret
)) {
3390 ret
= RXAFS_Link (conn
->connection
,
3391 &dir_entry
->fid
.fid
,
3393 &existing_entry
->fid
.fid
,
3397 if (host_downp(ret
)) {
3400 free_fs_server_context (&context
);
3401 arla_warn (ADEBFCACHE
, ret
, "Link");
3408 free_fs_server_context (&context
);
3410 if (host_downp(ret
)) {
3415 update_entry (dir_entry
, &status
, NULL
, &volsync
,
3418 update_entry (existing_entry
, &new_status
, NULL
, NULL
,
3424 AssertExclLocked(&dir_entry
->lock
);
3429 * Remove a file from a directory.
3433 remove_file (FCacheEntry
*dir_entry
, const char *name
, CredCacheEntry
*ce
)
3436 ConnCacheEntry
*conn
;
3437 AFSFetchStatus status
;
3439 fs_server_context context
;
3441 AssertExclLocked(&dir_entry
->lock
);
3443 if (connected_mode
== CONNECTED
) {
3445 ret
= init_fs_context(dir_entry
, ce
, &context
);
3449 for (conn
= find_first_fs (&context
);
3451 conn
= find_next_fs (&context
, conn
, ret
)) {
3453 ret
= RXAFS_RemoveFile (conn
->connection
,
3454 &dir_entry
->fid
.fid
,
3458 if (host_downp(ret
)) {
3461 free_fs_server_context (&context
);
3462 arla_warn (ADEBFCACHE
, ret
, "RemoveFile");
3469 free_fs_server_context (&context
);
3471 if (host_downp(ret
))
3479 status
= dir_entry
->status
;
3483 ret
= fcache_get_fbuf (dir_entry
, &fd
, &the_fbuf
,
3484 O_RDONLY
, FBUF_READ
|FBUF_SHARED
);
3488 ret
= fdir_lookup(&the_fbuf
, &dir_entry
->fid
, name
, &child_fid
);
3490 FCacheEntry
*child_entry
= NULL
;
3491 uint32_t disco_id
= 0;
3493 ret
= fcache_find(&child_entry
, child_fid
);
3495 disco_id
= child_entry
->disco_id
;
3497 disco_id
= disco_unlink(&dir_entry
->fid
, &child_fid
,
3501 child_entry
->disco_id
= disco_id
;
3502 fcache_release(child_entry
);
3507 fbuf_end (&the_fbuf
);
3512 update_entry (dir_entry
, &status
, NULL
, &volsync
,
3518 AssertExclLocked(&dir_entry
->lock
);
3523 * Remove a directory from a directory.
3527 remove_directory (FCacheEntry
*dir_entry
,
3532 ConnCacheEntry
*conn
;
3533 AFSFetchStatus status
;
3535 fs_server_context context
;
3537 AssertExclLocked(&dir_entry
->lock
);
3539 if (connected_mode
!= CONNECTED
)
3542 ret
= init_fs_context(dir_entry
, ce
, &context
);
3546 for (conn
= find_first_fs (&context
);
3548 conn
= find_next_fs (&context
, conn
, ret
)) {
3550 ret
= RXAFS_RemoveDir (conn
->connection
,
3551 &dir_entry
->fid
.fid
,
3555 if (host_downp(ret
)) {
3558 free_fs_server_context (&context
);
3559 arla_warn (ADEBFCACHE
, ret
, "RemoveDir");
3566 free_fs_server_context (&context
);
3568 if (host_downp(ret
)) {
3573 update_entry (dir_entry
, &status
, NULL
, &volsync
,
3579 AssertExclLocked(&dir_entry
->lock
);
3588 rename_file (FCacheEntry
*old_dir
,
3589 const char *old_name
,
3590 FCacheEntry
*new_dir
,
3591 const char *new_name
,
3594 int ret
= ARLA_CALL_DEAD
;
3595 ConnCacheEntry
*conn
;
3596 AFSFetchStatus orig_status
, new_status
;
3598 fs_server_context context
;
3600 AssertExclLocked(&old_dir
->lock
);
3601 AssertExclLocked(&new_dir
->lock
);
3603 if (connected_mode
!= CONNECTED
)
3606 ret
= init_fs_context(old_dir
, ce
, &context
);
3610 for (conn
= find_first_fs (&context
);
3612 conn
= find_next_fs (&context
, conn
, ret
)) {
3614 ret
= RXAFS_Rename (conn
->connection
,
3622 if (host_downp(ret
)) {
3625 free_fs_server_context (&context
);
3626 arla_warn (ADEBFCACHE
, ret
, "Rename");
3633 free_fs_server_context (&context
);
3635 if (host_downp(ret
)) {
3640 update_entry (old_dir
, &orig_status
, NULL
, &volsync
,
3643 update_entry (new_dir
, &new_status
, NULL
, &volsync
,
3649 AssertExclLocked(&old_dir
->lock
);
3650 AssertExclLocked(&new_dir
->lock
);
3655 * Return the fid to the root.
3659 getroot (VenusFid
*res
, CredCacheEntry
*ce
)
3663 const char *root_volume
= volcache_get_rootvolume ();
3665 const char *this_cell
= cell_getthiscell ();
3666 int32_t this_cell_id
;
3668 if (dynroot_enablep()) {
3669 this_cell
= "dynroot";
3670 this_cell_id
= dynroot_cellid();
3672 this_cell_id
= cell_name2num (this_cell
);
3673 if (this_cell_id
== -1)
3674 arla_errx (1, ADEBERROR
, "cell %s does not exist", this_cell
);
3677 ret
= volcache_getbyname (root_volume
, this_cell_id
, ce
, &ve
, NULL
);
3679 arla_warn (ADEBWARN
, ret
,
3680 "Cannot find the root volume (%s) in cell %s",
3681 root_volume
, this_cell
);
3685 fid
.Cell
= this_cell_id
;
3686 if (ve
->entry
.flags
& VLF_ROEXISTS
) {
3687 fid
.fid
.Volume
= ve
->entry
.volumeId
[ROVOL
];
3688 } else if (ve
->entry
.flags
& VLF_RWEXISTS
) {
3689 arla_warnx(ADEBERROR
,
3690 "getroot: %s in cell %s is missing a RO clone, not good",
3691 root_volume
, this_cell
);
3692 fid
.fid
.Volume
= ve
->entry
.volumeId
[RWVOL
];
3694 arla_errx(1, ADEBERROR
,
3695 "getroot: %s in cell %s has no RW or RO clone?",
3696 root_volume
, this_cell
);
3698 fid
.fid
.Vnode
= fid
.fid
.Unique
= 1;
3707 * Return the type for this volume.
3711 getvoltype(int32_t volid
, const VolCacheEntry
*ve
)
3715 for (i
= RWVOL
; i
<= BACKVOL
; ++i
)
3716 if (ve
->entry
.volumeId
[i
] == volid
)
3719 return -1; /* NOT REACHED */
3723 * Return the entry for `fid' or NULL.
3727 fcache_find (FCacheEntry
**res
, VenusFid fid
)
3729 *res
= find_entry_nolock (fid
);
3732 ObtainWriteLock (&(*res
)->lock
);
3737 * Return the entry for `fid'. If it's not cached, add it.
3741 fcache_get (FCacheEntry
**res
, VenusFid fid
, CredCacheEntry
*ce
)
3750 error
= fcache_find(&old
, fid
);
3752 assert (old
->flags
.usedp
);
3757 error
= volcache_getbyid (fid
.fid
.Volume
, fid
.Cell
, ce
, &vol
, NULL
);
3759 if (connected_mode
== DISCONNECTED
&& error
== ENOENT
)
3764 e
= find_free_entry ();
3767 error
= fcache_find(&old
, fid
);
3769 AssertExclLocked(&e
->lock
);
3770 ReleaseWriteLock (&e
->lock
);
3772 e
->lru_le
= listaddtail (lrulist
, e
);
3775 assert (old
->flags
.usedp
);
3784 e
->wanted_length
= 0;
3785 e
->fetched_length
= 0;
3786 memset (&e
->status
, 0, sizeof(e
->status
));
3787 memset (&e
->callback
, 0, sizeof(e
->callback
));
3788 memset (&e
->volsync
, 0, sizeof(e
->volsync
));
3789 for (i
= 0; i
< NACCESS
; i
++) {
3790 e
->acccache
[i
].cred
= ARLA_NO_AUTH_CRED
;
3791 e
->acccache
[i
].access
= 0;
3794 e
->flags
.usedp
= TRUE
;
3795 e
->flags
.attrp
= FALSE
;
3796 e
->flags
.attrusedp
= FALSE
;
3797 e
->flags
.datausedp
= FALSE
;
3798 e
->flags
.extradirp
= FALSE
;
3799 e
->flags
.mountp
= FALSE
;
3800 e
->flags
.fake_mp
= FALSE
;
3801 e
->flags
.vol_root
= FALSE
;
3802 e
->flags
.kernelp
= FALSE
;
3803 e
->flags
.sentenced
= FALSE
;
3804 e
->flags
.silly
= FALSE
;
3806 memset (&e
->parent
, 0, sizeof(e
->parent
));
3807 e
->lru_le
= listaddhead (lrulist
, e
);
3809 e
->invalid_ptr
= -1;
3811 e
->priority
= fprio_get(fid
);
3815 hashtabadd (hashtab
, e
);
3822 * Release the lock on `e' and mark it as stale if it has been sentenced.
3826 fcache_release (FCacheEntry
*e
)
3828 AssertExclLocked(&e
->lock
);
3830 ReleaseWriteLock (&e
->lock
);
3832 if (e
->flags
.sentenced
) {
3833 AFSCallBack broken_callback
= {0, 0, CBDROPPED
};
3835 stale (e
, broken_callback
);
3836 e
->flags
.sentenced
= FALSE
;
3845 uptodatep (FCacheEntry
*e
)
3848 assert (e
->flags
.usedp
);
3850 if (connected_mode
!= CONNECTED
&&
3851 connected_mode
!= FETCH_ONLY
)
3854 gettimeofday(&tv
, NULL
);
3856 if (tv
.tv_sec
< e
->callback
.ExpirationTime
&&
3857 e
->callback
.CallBackType
!= CBDROPPED
&&
3858 (e
->callback
.CallBackType
!= 0
3859 || e
->volume
->volsync
.spare1
!= e
->volsync
.spare1
))
3866 * The idea is that we start to stat everything after the prefered
3867 * entry, everything before that is probably not useful to get, the
3868 * user is probably trying to stat() everything _after_ that node.
3869 * This might be somewhat bogus, but we dont care (for now).
3873 int len
; /* used entries in fids and names */
3874 AFSFid fids
[AFSCBMAX
]; /* fids to fetch */
3875 char *names
[AFSCBMAX
]; /* names it install */
3876 AFSFid
*used
; /* do we have a prefered node */
3877 CredCacheEntry
*ce
; /* cred to use */
3881 struct nnpfs_message_installnode node
;
3882 struct nnpfs_message_installattr attr
;
3883 } nnpfs_message_install_node_attr
;
3886 bulkstat_help_func (VenusFid
*fid
, const char *name
, void *ptr
)
3888 struct bulkstat
*bs
= (struct bulkstat
*) ptr
;
3894 if (bs
->len
> fcache_bulkstatus_num
)
3897 /* Ignore . and .. */
3898 if (strcmp(name
, ".") == 0 || strcmp(name
, "..") == 0)
3902 * Do we have a prefered node, and is this the one. If we don't know
3903 * the name of the node (ie bs.names[0] == NULL), fill it in.
3904 * Set bs->used to NULL it indicate that we should start stat stuff
3905 * from here, remeber that bs->len == 1 if bs->used is set.
3908 if (memcmp(bs
->used
, &fid
->fid
, sizeof(fid
->fid
)) == 0) {
3909 if (bs
->names
[0] == NULL
)
3910 bs
->names
[0] = strdup (name
);
3911 bs
->used
= NULL
; /* stat everything after this */
3917 * Already cached for this pag ?
3920 e
= (FCacheEntry
*)hashtabsearch (hashtab
, (void *)&key
);
3925 && findaccess (bs
->ce
->cred
, e
->acccache
, &ae
) == TRUE
) {
3926 arla_warnx (ADEBFCACHE
,
3927 "bulkstat_help_func: already cached "
3928 "(%d.%d.%d.%d) name: %s",
3929 fid
->Cell
, fid
->fid
.Volume
, fid
->fid
.Vnode
,
3930 fid
->fid
.Unique
, name
);
3934 if (fcache_enable_bulkstatus
== 2) {
3935 /* cache the name for the installnode */
3936 bs
->names
[bs
->len
] = strdup (name
);
3937 if (bs
->names
[bs
->len
] == NULL
)
3940 bs
->names
[bs
->len
] = NULL
;
3944 bs
->fids
[bs
->len
] = fid
->fid
;
3951 * Do bulkstat for ``parent_entry''. Make sure that ``prefered_entry''
3952 * is in the list of fids it not NULL, and it ``prefered_name'' is NULL
3953 * try to find it in the list files in the directory.
3955 * Entry Success Failure
3956 * parent_entry locked locked locked
3957 * prefered_entry locked locked locked
3958 * or if NULL if set to NULL must not be locked
3959 * prefered_fid related fcache-entry must not be locked
3964 get_attr_bulk (FCacheEntry
*parent_entry
,
3965 FCacheEntry
*prefered_entry
,
3966 VenusFid
*prefered_fid
,
3967 const char *prefered_name
,
3970 fs_server_context context
;
3971 ConnCacheEntry
*conn
= NULL
;
3981 struct collect_stat collectstat
;
3983 arla_warnx (ADEBFCACHE
, "get_attr_bulk");
3985 AssertExclLocked(&parent_entry
->lock
);
3987 AssertExclLocked(&prefered_entry
->lock
);
3989 if (fcache_enable_bulkstatus
== 0)
3992 if (parent_entry
->length
== 0) {
3993 arla_warnx (ADEBFCACHE
, "get_attr_bulk: parent doesn't have data");
3999 memset (bs
.names
, 0, sizeof(bs
.names
));
4000 memset (bs
.fids
, 0, sizeof(bs
.fids
));
4006 * If we have a prefered_entry, and that to the first entry in the
4007 * array. This is used later. If we find the prefered_entry in the
4008 * directory-structure its ignored.
4012 arla_warnx (ADEBFCACHE
, "get_attr_bulk: using prefered_entry");
4013 bs
.used
= &prefered_fid
->fid
;
4014 fids
.val
[bs
.len
] = prefered_fid
->fid
;
4015 if (prefered_name
!= NULL
) {
4016 bs
.names
[bs
.len
] = strdup(prefered_name
);
4017 if (bs
.names
[bs
.len
] == NULL
)
4020 bs
.names
[bs
.len
] = NULL
;
4025 ret
= fcache_get_fbuf (parent_entry
, &fd
, &the_fbuf
,
4026 O_RDONLY
, FBUF_READ
|FBUF_SHARED
);
4030 ret
= fdir_readdir (&the_fbuf
,
4035 fbuf_end (&the_fbuf
);
4043 * Don't do BulkStatus when fids.len == 0 since we should never do it.
4044 * There should at least be the node that we want in the BulkStatus.
4047 if (fids
.len
== 0) {
4049 arla_warnx (ADEBERROR
,
4051 "prefered_fid not found in dir");
4052 /* XXX MAGIC send it back so we don't do it again soon */
4053 parent_entry
->hits
-= 64;
4059 * XXX if there is a prefered fid, and and we didn't find the name for it
4063 if (prefered_fid
&& bs
.names
[0] == NULL
) {
4064 arla_warnx (ADEBFCACHE
,
4065 "get_attr_bulk: didn't find prefered_fid's name");
4070 ret
= ARLA_CALL_DEAD
;
4072 ret
= init_fs_context(parent_entry
, ce
, &context
);
4076 for (conn
= find_first_fs (&context
);
4078 conn
= find_next_fs (&context
, conn
, ret
)) {
4082 stats
.len
= cbs
.len
= 0;
4084 collectstats_start(&collectstat
);
4085 ret
= RXAFS_BulkStatus (conn
->connection
, &fids
, &stats
, &cbs
, &sync
);
4086 collectstats_stop(&collectstat
, parent_entry
, conn
,
4087 find_partition(&context
),
4088 arla_STATISTICS_REQTYPE_BULKSTATUS
, fids
.len
);
4094 if (host_downp(ret
)) {
4097 free_fs_server_context(&context
);
4098 arla_warn(ADEBFCACHE
, ret
, "BulkStatus");
4106 free_fs_server_context (&context
);
4113 arla_warnx (ADEBFCACHE
,"get_attr_bulk: BulkStatus returned %d",ret
);
4115 len
= min(fids
.len
, min(stats
.len
, cbs
.len
));
4118 * Save results of bulkstatus
4125 fcache_counter
.fetch_attr_bulk
+= len
;
4127 fid
.Cell
= parent_entry
->fid
.Cell
;
4128 for (i
= 0; i
< len
&& ret
== 0; i
++) {
4130 fid
.fid
= fids
.val
[i
];
4132 if (VenusFid_cmp(prefered_fid
, &fid
) == 0) {
4135 e
= find_entry_nolock (fid
);
4136 if (e
!= NULL
&& CheckLock(&e
->lock
) != 0)
4139 ret
= fcache_get (&e
, fid
, ce
);
4143 update_attr_entry (e
,
4149 e
->parent
= parent_entry
->fid
;
4150 if (prefered_entry
!= e
) {
4157 * Insert result into kernel
4160 if (fcache_enable_bulkstatus
== 2 && ret
== 0) {
4161 nnpfs_message_install_node_attr msg
[AFSCBMAX
];
4162 struct nnpfs_msg_node
*node
;
4163 nnpfs_handle
*parent
;
4168 fid
.Cell
= parent_entry
->fid
.Cell
;
4169 for (i
= 0 , j
= 0; i
< len
&& ret
== 0; i
++) {
4172 fid
.fid
= fids
.val
[i
];
4174 if (VenusFid_cmp(prefered_fid
, &fid
) == 0) {
4177 e
= find_entry_nolock (fid
);
4178 if (e
!= NULL
&& CheckLock(&e
->lock
) != 0)
4181 ret
= fcache_get (&e
, fid
, ce
);
4187 arla_warnx (ADEBFCACHE
, "installing %d.%d.%d\n",
4191 assert_flag(e
,kernelp
);
4192 e
->flags
.attrusedp
= TRUE
;
4195 * Its its already installed, just update with installattr
4198 e
->tokens
|= NNPFS_ATTR_R
;
4200 if (!e
->flags
.kernelp
|| !e
->flags
.datausedp
)
4201 tokens
&= ~NNPFS_DATA_MASK
;
4203 if (e
->flags
.kernelp
) {
4204 msg
[j
].attr
.header
.opcode
= NNPFS_MSG_INSTALLATTR
;
4205 node
= &msg
[j
].attr
.node
;
4208 msg
[j
].node
.header
.opcode
= NNPFS_MSG_INSTALLNODE
;
4209 node
= &msg
[j
].node
.node
;
4210 parent
= &msg
[j
].node
.parent_handle
;
4211 e
->flags
.kernelp
= TRUE
;
4212 strlcpy (msg
[j
].node
.name
, bs
.names
[i
],
4213 sizeof(msg
[j
].node
.name
));
4215 node
->tokens
= tokens
;
4218 * Don't install symlink since they might be
4222 if (e
->status
.FileType
!= TYPE_LINK
) {
4223 fcacheentry2nnpfsnode (&e
->fid
,
4227 parent_entry
->acccache
,
4228 FCACHE2NNPFSNODE_ALL
);
4231 *parent
= *(struct nnpfs_handle
*) &parent_entry
->fid
;
4234 if (prefered_entry
!= e
)
4239 * Install if there is no error and we have something to install
4242 if (ret
== 0 && j
!= 0)
4243 ret
= nnpfs_send_message_multiple_list (kernel_fd
,
4244 (struct nnpfs_message_header
*) msg
,
4247 /* We have what we wanted, ignore errors */
4248 if (ret
&& i
> 0 && prefered_entry
)
4256 for (i
= 0 ; i
< bs
.len
&& ret
== 0; i
++)
4262 arla_warnx (ADEBFCACHE
, "get_attr_bulk: returned %d", ret
);
4269 * fetch attributes for the note `entry' with the rights `ce'. If
4270 * `parent_entry' is not NULL, it is used for doing bulkstatus when
4271 * guess is necessary. If there is a named associated with `entry' it
4272 * should be filled into `prefered_name' as that will be used for
4273 * guessing that nodes should be bulkstat:ed.
4275 * If there is no bulkstatus done, a plain FetchStatus is done.
4279 fcache_verify_attr (FCacheEntry
*entry
, FCacheEntry
*parent
,
4280 const char *prefered_name
, CredCacheEntry
* ce
)
4284 if (dynroot_is_dynrootp (entry
))
4285 return dynroot_get_attr (entry
, ce
);
4287 if (entry
->flags
.usedp
4288 && entry
->flags
.attrp
4290 && findaccess (ce
->cred
, entry
->acccache
, &ae
) == TRUE
)
4292 arla_warnx (ADEBFCACHE
, "fcache_get_attr: have attr");
4293 fcache_counter
.fetch_attr_cached
++;
4298 * XXX is this right ?
4299 * Dont ask fileserver if this file is deleted
4301 if (entry
->flags
.silly
) {
4302 entry
->tokens
|= NNPFS_ATTR_R
;
4303 entry
->flags
.attrp
= TRUE
;
4307 if (connected_mode
== DISCONNECTED
) {
4308 if (entry
->flags
.attrp
) {
4310 findaccess(ce
->cred
, entry
->acccache
, &ae
);
4311 ae
->cred
= ce
->cred
;
4312 ae
->access
= 0x7f; /* XXXDISCO */
4320 * If there is no parent, `entry' is a root-node, or the parent is
4321 * un-initialized, don't bother bulkstatus.
4324 && entry
->fid
.fid
.Vnode
!= 1
4325 && entry
->fid
.fid
.Unique
!= 1
4326 && !entry
->flags
.mountp
4327 && !entry
->flags
.fake_mp
4328 && entry
->parent
.Cell
!= 0
4329 && entry
->parent
.fid
.Volume
!= 0
4330 && entry
->parent
.fid
.Vnode
!= 0
4331 && entry
->parent
.fid
.Unique
!= 0)
4334 * Check if the entry is used, that means that
4335 * there is greater chance that we we'll succeed
4336 * when doing bulkstatus.
4339 if (parent
->hits
++ > fcache_bulkstatus_num
&&
4340 parent
->flags
.datausedp
) {
4343 arla_warnx (ADEBFCACHE
, "fcache_get_attr: doing bulk get_attr");
4345 error
= get_attr_bulk (parent
,
4348 /* magic calculation when we are going to do next bulkstat */
4357 * We got here because the bulkstatus failed, didn't want to do a
4358 * bulkstatus or we didn't get a parent for the entry
4361 arla_warnx (ADEBFCACHE
, "fcache_get_attr: doing read_attr");
4363 return read_attr (entry
, ce
);
4369 * Make sure that `e' has attributes and that they are up-to-date.
4370 * `e' must be write-locked.
4375 do_read_data (FCacheEntry
*e
, CredCacheEntry
*ce
)
4377 int ret
= ARLA_CALL_DEAD
;
4378 fs_server_context context
;
4379 ConnCacheEntry
*conn
;
4381 if (connected_mode
== DISCONNECTED
)
4384 ret
= init_fs_context(e
, ce
, &context
);
4388 for (conn
= find_first_fs (&context
);
4390 conn
= find_next_fs (&context
, conn
, ret
)) {
4391 ret
= read_data (e
, conn
, ce
, find_partition(&context
));
4392 if (!try_next_fs (ret
, &e
->fid
))
4395 free_fs_server_context (&context
);
4397 if (host_downp(ret
))
4403 * Make sure that `e' has file data and is up-to-date.
4407 fcache_verify_data (FCacheEntry
*e
, CredCacheEntry
*ce
)
4409 ConnCacheEntry
*conn
= NULL
;
4411 fs_server_context context
;
4413 assert (e
->flags
.usedp
);
4414 AssertExclLocked(&e
->lock
);
4416 if (dynroot_is_dynrootp (e
))
4417 return dynroot_get_data (e
, ce
);
4419 /* Don't get data for deleted files */
4423 if (e
->flags
.attrp
&& uptodatep(e
)) {
4424 if (e
->wanted_length
<= e
->fetched_length
) {
4425 fcache_counter
.fetch_data_cached
++;
4428 return do_read_data (e
, ce
);
4430 ret
= do_read_attr (e
, ce
, &conn
, &context
);
4433 if (e
->wanted_length
<= e
->fetched_length
) {
4434 fcache_counter
.fetch_data_cached
++;
4435 free_fs_server_context (&context
);
4439 ret
= read_data (e
, conn
, ce
, find_partition(&context
));
4440 free_fs_server_context (&context
);
4445 * Fetch `fid' with data, returning the cache entry in `res'.
4446 * note that `fid' might change.
4450 fcache_get_data (FCacheEntry
**e
, CredCacheEntry
**ce
,
4451 uint64_t wanted_length
)
4455 if ((*e
)->flags
.fake_mp
) {
4457 FCacheEntry
*new_root
;
4459 ret
= resolve_mp (e
, &new_fid
, ce
);
4463 ret
= fcache_get (&new_root
, new_fid
, *ce
);
4467 ret
= fcache_verify_attr (new_root
, NULL
, NULL
, *ce
);
4469 fcache_release (new_root
);
4472 (*e
)->flags
.fake_mp
= FALSE
;
4473 (*e
)->flags
.mountp
= TRUE
;
4474 (*e
)->status
.FileType
= TYPE_LINK
;
4475 update_fid ((*e
)->fid
, *e
, new_fid
, new_root
);
4476 fcache_release (*e
);
4478 install_attr (*e
, FCACHE2NNPFSNODE_ALL
);
4481 if (wanted_length
) {
4482 (*e
)->wanted_length
= wanted_length
;
4485 * XXX remove this case, attr should either be known already
4486 * here, or we should just fetch `whole file'/next block.
4489 ret
= fcache_verify_attr (*e
, NULL
, NULL
, *ce
);
4493 if ((*e
)->length
== 0 || !uptodatep(*e
)) {
4494 (*e
)->wanted_length
= fcache_get_status_length(&(*e
)->status
);
4498 ret
= fcache_verify_data (*e
, *ce
);
4503 * Helper function for followmountpoint.
4504 * Given the contents of a mount-point, figure out the cell and volume name.
4506 * ``mp'' must be writeable and should not be used afterwards.
4507 * ``*volname'' is a pointer to somewhere in the mp string.
4508 * ``cell'' should be set before function is called to default cell.
4512 parse_mountpoint (char *mp
, size_t len
, int32_t *cell
, char **volname
)
4517 colon
= strchr (mp
, ':');
4518 if (colon
!= NULL
) {
4520 *cell
= cell_name2num (mp
+ 1);
4531 * Used by followmountpoint to figure out what clone of a volume
4534 * Given a `volname', `cell', it uses the given `ce', `mount_symbol'
4535 * and `parent_type' to return a volume id in `volume'.
4540 * BK + "backup" -> fail
4546 * this_type = "" | "readonly" | "backup"
4547 * parent_type = RW | RO | BK
4548 * mount_symbol = "#" | "%"
4552 find_volume (const char *volname
, int32_t cell
,
4553 CredCacheEntry
*ce
, char mount_symbol
, int parent_type
,
4554 uint32_t *volid
, VolCacheEntry
**ve
)
4560 res
= volcache_getbyname (volname
, cell
, ce
, ve
, &this_type
);
4564 assert (this_type
== RWVOL
||
4565 this_type
== ROVOL
||
4566 this_type
== BACKVOL
);
4568 if (this_type
== ROVOL
) {
4569 if (!((*ve
)->entry
.flags
& VLF_ROEXISTS
)) {
4570 volcache_free (*ve
);
4573 result_type
= ROVOL
;
4574 } else if (this_type
== BACKVOL
&& parent_type
== BACKVOL
) {
4575 volcache_free (*ve
);
4577 } else if (this_type
== BACKVOL
) {
4578 if (!((*ve
)->entry
.flags
& VLF_BOEXISTS
)) {
4579 volcache_free (*ve
);
4582 result_type
= BACKVOL
;
4583 } else if (this_type
== RWVOL
&&
4584 parent_type
!= RWVOL
&&
4585 mount_symbol
== '#') {
4586 if ((*ve
)->entry
.flags
& VLF_ROEXISTS
)
4587 result_type
= ROVOL
;
4588 else if ((*ve
)->entry
.flags
& VLF_RWEXISTS
)
4589 result_type
= RWVOL
;
4591 volcache_free (*ve
);
4595 if ((*ve
)->entry
.flags
& VLF_RWEXISTS
)
4596 result_type
= RWVOL
;
4597 else if ((*ve
)->entry
.flags
& VLF_ROEXISTS
)
4598 result_type
= ROVOL
;
4600 volcache_free (*ve
);
4604 *volid
= (*ve
)->entry
.volumeId
[result_type
];
4609 * Set `fid' to point to the root of the volume pointed to by the
4610 * mount-point in (buf, len).
4612 * If succesful, `fid' will be updated to the root of the volume, and
4613 * `ce' will point to a cred in the new cell.
4617 get_root_of_volume (VenusFid
*fid
, const VenusFid
*parent
,
4618 VolCacheEntry
*volume
,
4619 CredCacheEntry
**ce
,
4620 char *buf
, size_t len
)
4622 VenusFid oldfid
= *fid
;
4627 long parent_type
, voltype
;
4634 res
= parse_mountpoint (buf
, len
, &cell
, &volname
);
4639 * If this is a cross-cell mountpoint we need new credentials.
4642 if ((*ce
)->cell
!= cell
) {
4643 CredCacheEntry
*new_ce
;
4645 new_ce
= cred_get(cell
, (*ce
)->cred
, CRED_ANY
);
4652 parent_type
= getvoltype (fid
->fid
.Volume
, volume
);
4653 mount_symbol
= *buf
;
4655 res
= find_volume (volname
, cell
, *ce
, mount_symbol
,
4656 parent_type
, &volid
, &ve
);
4661 * Create the new fid. The root of a volume always has
4662 * (Vnode, Unique) = (1,1)
4666 fid
->fid
.Volume
= volid
;
4667 fid
->fid
.Vnode
= fid
->fid
.Unique
= 1;
4670 * Check if we are looking up ourself, if we are, just return.
4673 if (VenusFid_cmp(fid
, parent
) == 0) {
4678 res
= fcache_get (&e
, *fid
, *ce
);
4685 * Root nodes are a little bit special. We keep track of
4686 * their parent in `parent' so that `..' can be handled
4690 e
->flags
.vol_root
= TRUE
;
4691 e
->parent
= *parent
;
4693 voltype
= getvoltype (fid
->fid
.Volume
, ve
);
4694 if (ve
->parent
[voltype
].volume
== NULL
) {
4695 ve
->parent
[voltype
].fid
= *parent
;
4696 ve
->parent
[voltype
].mp_fid
= oldfid
;
4698 volcache_volref (ve
, volume
, voltype
);
4705 * If this entry is a mount point, set the fid data to
4706 * the root directory of the volume it's pointing at,
4707 * otherwise just leave it.
4709 * Mount points are symbol links with the following contents:
4711 * '#' | '%' [ cell ':' ] volume-name [ '.' ]
4713 * This function tries to do a minimal amount of work. It always has
4714 * to fetch the attributes of `fid' and if it's a symbolic link, the
4719 followmountpoint (VenusFid
*fid
, const VenusFid
*parent
, FCacheEntry
*parent_e
,
4720 CredCacheEntry
**ce
)
4726 * Get the node for `fid' and verify that it's a symbolic link
4727 * with the correct bits. Otherwise, just return the old
4728 * `fid' without any change.
4731 ret
= fcache_get (&e
, *fid
, *ce
);
4735 e
->parent
= *parent
;
4736 ret
= fcache_verify_attr (e
, parent_e
, NULL
, *ce
);
4742 if (e
->flags
.mountp
)
4743 ret
= resolve_mp (&e
, fid
, ce
);
4750 * actually resolve a mount-point
4754 resolve_mp (FCacheEntry
**e
, VenusFid
*ret_fid
, CredCacheEntry
**ce
)
4756 VenusFid fid
= (*e
)->fid
;
4763 assert ((*e
)->flags
.fake_mp
|| (*e
)->flags
.mountp
);
4764 AssertExclLocked(&(*e
)->lock
);
4766 (*e
)->wanted_length
= fcache_get_status_length(&(*e
)->status
);
4768 ret
= fcache_verify_data (*e
, *ce
);
4772 length
= fcache_get_status_length(&(*e
)->status
);
4774 fd
= fcache_open_file (*e
, O_RDONLY
);
4778 ret
= fbuf_create (&the_fbuf
, fd
, length
,
4779 FBUF_READ
|FBUF_WRITE
|FBUF_PRIVATE
);
4784 buf
= fbuf_buf (&the_fbuf
);
4786 ret
= get_root_of_volume (&fid
, &(*e
)->parent
, (*e
)->volume
,
4789 fbuf_end (&the_fbuf
);
4802 print_entry (void *ptr
, void *arg
)
4804 FCacheEntry
*e
= (FCacheEntry
*)ptr
;
4806 arla_log(ADEBVLOG
, "(%d, %u, %u, %u)" "%s%s%s%s"
4807 "%s%s%s%s" "%s%s%s%s length: %llu",
4809 e
->fid
.fid
.Volume
, e
->fid
.fid
.Vnode
, e
->fid
.fid
.Unique
,
4811 e
->flags
.usedp
?" used":"",
4812 e
->flags
.attrp
?" attr":"",
4813 e
->length
!= 0 ?" data":"",
4814 e
->flags
.attrusedp
?" attrused":"",
4816 e
->flags
.datausedp
?" dataused":"",
4817 e
->flags
.extradirp
?" extradir":"",
4818 e
->flags
.mountp
?" mount":"",
4819 e
->flags
.kernelp
?" kernel":"",
4821 e
->flags
.sentenced
?" sentenced":"",
4822 e
->flags
.silly
?" silly":"",
4823 e
->flags
.fake_mp
? " fake mp" : "",
4824 e
->flags
.vol_root
? " vol root" : "",
4825 (unsigned long long)fcache_get_status_length(&e
->status
));
4835 fcache_status (void)
4837 arla_log(ADEBVLOG
, "%lu (%lu-/%lu)-%lu) files"
4838 "%lu (%lu-%lu) bytes\n",
4839 usedvnodes
, lowvnodes
, current_vnodes
, highvnodes
,
4840 (long)usedbytes
, (long)lowbytes
, (long)highbytes
);
4841 hashtabforeach (hashtab
, print_entry
, NULL
);
4849 fcache_update_length (FCacheEntry
*e
, uint64_t len
, uint64_t have_len
)
4851 AssertExclLocked(&e
->lock
);
4853 assert (len
>= e
->length
|| e
->length
- len
<= usedbytes
);
4854 assert (have_len
<= len
);
4856 usedbytes
= usedbytes
- e
->length
+ len
;
4858 e
->wanted_length
= min(have_len
,len
);
4859 e
->fetched_length
= have_len
;
4863 * Request an ACL and put it in opaque
4867 getacl(VenusFid fid
,
4872 ConnCacheEntry
*conn
;
4873 AFSFetchStatus status
;
4876 fs_server_context context
;
4881 if (connected_mode
!= CONNECTED
)
4884 ret
= fcache_get (&dire
, fid
, ce
);
4886 arla_warn (ADEBFCACHE
, ret
, "fcache_get");
4890 ret
= init_fs_context(dire
, ce
, &context
);
4894 for (conn
= find_first_fs (&context
);
4896 conn
= find_next_fs (&context
, conn
, ret
)) {
4898 ret
= RXAFS_FetchACL (conn
->connection
, &fid
.fid
,
4899 opaque
, &status
, &volsync
);
4906 if (!try_next_fs (ret
, &fid
))
4910 arla_warn (ADEBFCACHE
, ret
, "FetchACL");
4913 update_entry (dire
, &status
, NULL
, &volsync
,
4915 else if (host_downp(ret
))
4918 free_fs_server_context (&context
);
4919 fcache_release (dire
);
4924 * Store the ACL read from opaque
4926 * If the function return 0, ret_e is set to the dir-entry and must
4927 * be fcache_released().
4931 setacl(VenusFid fid
,
4934 FCacheEntry
**ret_e
)
4937 ConnCacheEntry
*conn
;
4938 AFSFetchStatus status
;
4941 fs_server_context context
;
4943 if (connected_mode
!= CONNECTED
)
4946 ret
= fcache_get (&dire
, fid
, ce
);
4948 arla_warn (ADEBFCACHE
, ret
, "fcache_get");
4952 ret
= init_fs_context(dire
, ce
, &context
);
4956 for (conn
= find_first_fs (&context
);
4958 conn
= find_next_fs (&context
, conn
, ret
)) {
4959 ret
= RXAFS_StoreACL (conn
->connection
, &fid
.fid
,
4960 opaque
, &status
, &volsync
);
4961 if (!try_next_fs (ret
, &fid
))
4965 arla_warn (ADEBFCACHE
, ret
, "StoreACL");
4968 update_entry (dire
, &status
, NULL
, &volsync
,
4970 else if (host_downp(ret
))
4973 free_fs_server_context (&context
);
4979 fcache_release (dire
);
4985 * Request volume status
4989 getvolstat(VenusFid fid
, CredCacheEntry
*ce
,
4990 AFSFetchVolumeStatus
*volstat
,
4991 char *volumename
, size_t volumenamesz
,
4996 ConnCacheEntry
*conn
;
4998 fs_server_context context
;
5000 if (connected_mode
!= CONNECTED
)
5003 ret
= fcache_get (&dire
, fid
, ce
);
5005 arla_warn (ADEBFCACHE
, ret
, "fcache_get");
5009 ret
= init_fs_context(dire
, ce
, &context
);
5013 for (conn
= find_first_fs (&context
);
5015 conn
= find_next_fs (&context
, conn
, ret
)) {
5016 ret
= RXAFS_GetVolumeStatus (conn
->connection
, fid
.fid
.Volume
,
5017 volstat
, volumename
, offlinemsg
,
5019 if (!try_next_fs (ret
, &fid
))
5023 arla_warn (ADEBFCACHE
, ret
, "GetVolumeStatus");
5024 free_fs_server_context (&context
);
5025 if (host_downp(ret
))
5027 if (ret
== 0 && volumename
[0] == '\0') {
5028 if (volcache_getname (fid
.fid
.Volume
, fid
.Cell
,
5029 volumename
, volumenamesz
) == -1)
5030 strlcpy(volumename
, "<unknown>", volumenamesz
);
5033 fcache_release (dire
);
5038 * Store volume status
5042 setvolstat(VenusFid fid
, CredCacheEntry
*ce
,
5043 AFSStoreVolumeStatus
*volstat
,
5049 ConnCacheEntry
*conn
;
5051 fs_server_context context
;
5053 if (connected_mode
!= CONNECTED
)
5056 ret
= fcache_get (&dire
, fid
, ce
);
5058 arla_warn (ADEBFCACHE
, ret
, "fcache_get");
5062 ret
= init_fs_context(dire
, ce
, &context
);
5066 for (conn
= find_first_fs (&context
);
5068 conn
= find_next_fs (&context
, conn
, ret
)) {
5069 ret
= RXAFS_SetVolumeStatus (conn
->connection
, fid
.fid
.Volume
,
5070 volstat
, volumename
, offlinemsg
,
5072 if (!try_next_fs (ret
, &fid
))
5076 if (host_downp(ret
))
5078 arla_warn (ADEBFCACHE
, ret
, "SetVolumeStatus");
5080 free_fs_server_context (&context
);
5082 fcache_release (dire
);
5087 * Get `fbuf' from `centry' that is opened with openflags
5088 * `open_flags' and fbuf flags with `fbuf_flags'
5090 * Assume that data is valid and `centry' is exclusive locked.
5094 fcache_get_fbuf (FCacheEntry
*centry
, int *fd
, fbuf
*fbuf
,
5095 int open_flags
, int fbuf_flags
)
5101 AssertExclLocked(¢ry
->lock
);
5103 *fd
= fcache_open_file (centry
, open_flags
);
5107 if (fstat (*fd
, &sb
)) {
5115 ret
= fbuf_create (fbuf
, *fd
, len
, fbuf_flags
);
5128 sum_node (List
*list
, Listitem
*li
, void *arg
)
5131 FCacheEntry
*e
= listdata (li
);
5140 fcache_calculate_usage (void)
5144 listiter (lrulist
, sum_node
, &size
);
5154 fcache_realfid (const FCacheEntry
*entry
)
5156 if (entry
->flags
.vol_root
5157 || (entry
->fid
.fid
.Vnode
== 1 && entry
->fid
.fid
.Unique
== 1)) {
5158 long voltype
= getvoltype(entry
->fid
.fid
.Volume
, entry
->volume
);
5159 return &entry
->volume
->parent
[voltype
].mp_fid
;
5170 check_dir (List
*list
, Listitem
*li
, void *arg
)
5172 FCacheEntry
*e
= listdata (li
);
5176 if (CheckLock(&e
->lock
) != 0)
5179 ObtainWriteLock (&e
->lock
);
5184 ret
= fcache_get_fbuf (e
, &fd
, &the_fbuf
, O_RDONLY
, FBUF_READ
|FBUF_SHARED
);
5188 ret
= fdir_dirp(&the_fbuf
);
5190 fbuf_end (&the_fbuf
);
5193 if (e
->status
.FileType
== TYPE_DIR
)
5199 ReleaseWriteLock (&e
->lock
);
5205 * Verifies that directories seems to be directories and files doesn't
5206 * seems to be directories, note that false positives are
5207 * possible in the latter of these cases, so this should not be turned on
5212 fcache_check_dirs(void)
5214 listiter (lrulist
, check_dir
, NULL
);