📄 tfs_swap.c
字号:
#ifndef lintstatic char sccsid[] = "@(#)tfs_swap.c 1.1 92/07/30 Copyr 1988 Sun Micro";#endif/* * Copyright (c) 1988 Sun Microsystems, Inc. */#include <nse/util.h>#include "headers.h"#include "vnode.h"#include "tfs.h"#include "subr.h"#include "tfs_lists.h"#include <nse/param.h>#include <nse/stdio.h>/* * Once the TFS assigns a nodeid for a file, it has to remember that nodeid * forever until the mount is no longer active. The TFS can't forget about * any nodeids because the kernel can keep a vnode open for a file/directory * indefinitely, and there is no way for the TFS to query the kernel to * determine which files it is currently referencing. * * Since the TFS has to remember the nodeids of all files that have been * referenced, the TFS can grow without bound, and can grow very large * indeed if a large filesystem is referenced. Consequently, we need to * save the nodeids to files to save memory. * * The TFS's fhandle for a file contains the nodeid of the file and * the nodeid of the parent directory. Therefore, if we are careful * to never swap out the nodeid of a directory that contains files, we * will always be able to figure out the file that an fhandle refers to. * When the TFS receives a request to operate on a file which is in a * swapped-out directory, then the fhandle lookup for the file will fail. * Since the file's fhandle also contains the nodeid of the parent * directory, we will be able to look up the directory by its nodeid, * swap in the directory, then redo the fhandle lookup for the file. * (The fhtovp() routine implements this logic.) * * While we're saving nodeids, we might as well save all the cached * information for a directory so that we won't have to revalidate * the directory when it is swapped back in. So we save all the read-only * pnodes of the directory, and state information for the child vnodes. * Note that we keep all writeable pnodes in memory because it is possible * for one of the writeable layers of a swapped-out directory to be updated * through another environment, in which case we need to swap in the directory * to update it. When we swap out a directory pnode in the frontmost * filesystem, we swap the nodeids of all vnodes which have that pnode as * their frontmost pnode (there can be a maximum of MAX_NAMES such vnodes.) * * Format of the swap file:<tfsd's pid> <timestamp><dir nodeid #1> <dir nodeid #2><directory name> <sub-layer> .....<name> <nodeid #1> <nodeid #2> <layer> <w-o> <back-layer> <back w-o> <mtime> ..... (the last three fields are written out only if they need to be) *//* * Maximum # of front filesystem pnodes allowed to have all read-only pnodes * and child vnodes in memory. */#define MAX_RESIDENT_PNODES 30typedef struct Tfs_swap { long dir_nodeids[MAX_NAMES]; Nse_list directories; Nse_list children;} *Tfs_swap, Tfs_swap_rec;/* * LRU queue of pnodes. The LRU pnode is at the head of the queue. */static Nse_list pnode_queue;static struct pnode *tail_pnode;#ifdef TFSDEBUGint nswapin;int nswapout;int nswapouterr;#endif TFSDEBUGstatic int my_pid;static long my_timestamp;static void swap_out_directory();void swap_in_directory();static void save_readonly_pnodes();static void release_readonly_pnodes();static void restore_readonly_pnodes();static struct pnode *get_pnode_if_exists();static void save_child_vnodes();static void release_child_vnodes();static void restore_child_vnodes();static void restore_vnode();static Tfs_swap read_swapfile();static bool_t write_swapfile();static Nse_err read_dirpnode_entry();static Nse_err write_dirpnode_entry();static Nse_err read_vnode_entry();static Nse_err write_vnode_entry();static Tfs_swap swap_rec_create();static void swap_rec_destroy();static bool_t vnodelist_name_eq();/* * Routines to implement the LRU pnode queue. */void swqueue_use_pnode();void swqueue_add_pnode();static void swqueue_enqueue();void swqueue_dequeue();#ifdef TFSDEBUGvoid swqueue_print();static void print_enqueued_pnode();#endif TFSDEBUGvoid init_swap();static voidswap_out_directory(pp) struct pnode *pp;{ struct vnode *vnodes[MAX_NAMES]; char pn[MAXPATHLEN]; FILE *file; Tfs_swap swap; int i; Nse_err err; struct stat statb; bzero((char *) vnodes, sizeof vnodes); get_vnodes(pp, vnodes); if (vnodes[0] == NULL) { /* * Can happen if all the views of this pnode were * unmounted or flushed, but a reference still remains * for the pnode. (Because this pnode is for a root * vnode or is not the frontmost pnode for some other * vnode.) */ return; } ptopn(pp, pn); nse_pathcat(pn, NSE_TFS_SWAP_FILE); file = open_tfs_file(pn, "w", &err); if (file == NULL) { /* * Print a warning message iff the directory still exists. * (It's possible that we are trying to swap out a directory * in an environment which has been deleted, in which case * the mountd will unmount this directory soon.) */ *rindex(pn, '/') = '\0'; if (stat(pn, &statb) == 0) { nse_log_err_print(err); } return; } swap = swap_rec_create(); save_readonly_pnodes(vnodes[0], swap->directories); for (i = 0; i < MAX_NAMES && vnodes[i]; i++) {#ifdef TFSDEBUG dprint(tfsdebug, 4, "Swapping out [%d %d]\n", PARENT_VNODE(vnodes[i])->v_fhid, vnodes[i]->v_fhid);#endif TFSDEBUG swap->dir_nodeids[i] = vnodes[i]->v_fhid; save_child_vnodes(vnodes[i], swap->children, i); } /* * Don't swap the directory out if there was an error writing * the swap file (if, for example, the filesystem was full.) Note * that in such a case, the directory's pnodes and child vnodes * will stay in memory forever. Too bad. */ if (write_swapfile(pn, file, swap)) { for (i = 0; i < MAX_NAMES && vnodes[i]; i++) { release_child_vnodes(vnodes[i]); release_readonly_pnodes(vnodes[i]); } pp->p_swapped = TRUE; } else {#ifdef TFSDEBUG nswapouterr++;#endif TFSDEBUG } swap_rec_destroy(swap);#ifdef TFSDEBUG nswapout++;#endif TFSDEBUG}voidswap_in_directory(pp) struct pnode *pp;{ Tfs_swap swap; struct vnode *vp; int i; swap = read_swapfile(pp); if (swap == NULL) { struct vnode *vnodes[MAX_NAMES]; /* * This should never happen. If it does happen, then it * will probably be because another process besides the * tfsd has been removing .tfs_swap files. */ nse_log_message("warning: can't read swapfile"); print_pnode_path(pp); /* * Mark the dirs as invalid so that they will be revalidated. */ bzero((char *) vnodes, sizeof vnodes); get_vnodes(pp, vnodes); for (i = 0; i < MAX_NAMES && vnodes[i]; i++) { vnodes[i]->v_dir_valid = FALSE; } pp->p_swapped = FALSE; return; } for (i = 0; i < MAX_NAMES && swap->dir_nodeids[i] != 0; i++) { vp = fhandle_find((unsigned long)swap->dir_nodeids[i]); if (vp == NULL) { /* * Can happen if one view on a directory was * unmounted after being swapped out. */ continue; }#ifdef TFSDEBUG dprint(tfsdebug, 4, "Swapping in [%d %d]\n", PARENT_VNODE(vp)->v_fhid, vp->v_fhid);#endif TFSDEBUG if (nse_list_nelems(swap->directories) > 0) { restore_readonly_pnodes(vp, swap->directories); } restore_child_vnodes(vp, swap->children, i); if (!vp->v_is_mount_pt && PARENT_VNODE(vp)->v_pnode == NULL) { (void) recurse_lookup_pnode(PARENT_VNODE(vp)); } } swap_rec_destroy(swap); swqueue_add_pnode(pp); /* * It's important that we wait to clear the swapped flag until * after adding the pnode to the swap queue. It's possible that * enqueueing this pnode has forced this pnode's parent to be * swapped out. */ pp->p_swapped = FALSE;#ifdef TFSDEBUG nswapin++;#endif TFSDEBUG}static voidsave_readonly_pnodes(vp, list) struct vnode *vp; Nse_list list;{ struct pnode *pp; Filelist fl; char pn[MAXPATHLEN]; pp = get_pnode_if_exists(vp, vp->v_writeable + 1); while (pp) { fl = NSE_NEW(Filelist); ptopn(pp, pn); fl->fname = NSE_STRDUP(pn); fl->layer = pp->p_sub_layer; (void) nse_list_add_new_data(list, (Nse_opaque) fl); pp = get_next_pnode(vp, pp); }}static voidrelease_readonly_pnodes(vp) struct vnode *vp;{ struct pnode *pp; struct pnode *next_pp; struct pnode *front_pp; front_pp = get_pnode_if_exists(vp, vp->v_writeable); if (front_pp == NULL) { return; } pp = release_linknode(vp, front_pp); while (pp) { next_pp = release_linknode(vp, pp); free_pnode(pp); pp = next_pp; } set_next_pnode(vp, front_pp, (struct pnode *) NULL, (int) vp->v_writeable);}static voidrestore_readonly_pnodes(vp, list) struct vnode *vp; Nse_list list;{ struct pnode *front_pp = vp->v_pnode; struct pnode *pp; struct pnode *next_pp = NULL; Filelist fl; Nse_listelem elem; Nse_listelem end; front_pp = get_pnode_if_exists(vp, vp->v_writeable); if (front_pp == NULL) { /* * Can happen if a directory is flushed after being swapped * out. When we get to this point, the directory is being * swapped in just before it is going to be revalidated, so * don't bother reconstructing the read-only pnodes as * they will be rebuilt when the dir. is revalidated. */ return; } (void) release_linknode(vp, front_pp); NSE_LIST_ITERATE_REV(list, Filelist, fl, elem, end) { pp = path_to_pnode(fl->fname, (unsigned) fl->layer); set_next_pnode(vp, pp, next_pp, 0); next_pp = pp; } set_next_pnode(vp, front_pp, next_pp, 0); set_linknode_layers(vp);}/* * If a pnode exists for vnode 'vp' at layer 'layer', return it. */static struct pnode *get_pnode_if_exists(vp, layer) struct vnode *vp; unsigned layer;{ struct pnode *pp = vp->v_pnode; int i = 0; while (i < layer) { pp = get_next_pnode(vp, pp); if (pp == NULL) { return NULL; } i++; } return pp;}static voidsave_child_vnodes(pvp, list, index) struct vnode *pvp; Nse_list list; int index;{ struct vnode *vp; Vnodelist vl; for (vp = CHILD_VNODE(pvp); vp != NULL; vp = NEXT_VNODE(vp)) { if (CHILD_VNODE(vp) != NULL || (vp->v_pnode != NULL && vp->v_pnode->p_swapped)) { continue; } if (index == 0) { vl = NULL; } else { vl = (Vnodelist) nse_list_search(list, vnodelist_name_eq, vp->v_name); } if (vl != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -