📄 tfs_update.c
字号:
{ int result = 0; if (vp->v_layer == INVALID_LAYER) { return (0); } if (vp->v_layer < layer) { /* * if vp->v_back_layer < layer, do nothing; * vp->v_back_layer > layer impossible */ if (vp->v_back_layer == layer) { vp->v_back_layer = UNKNOWN_LAYER; vp->v_back_whited_out = FALSE; if (is_directory) { return (remove_or_whiteout_file(pvp, vp, layer, must_set_wo, is_directory, wo_listp, wo_status)); } } return (0); } if (CHILD_VNODE(vp) != NULL) { /* * This can happen if rmdir removes a directory which * contained whiteout vnodes, or if rename moves a * directory to a different parent directory. */ discard_child_vnodes(vp); } if (vp->v_whited_out) { return (0); } if (vp->v_layer == layer) { if (vp->v_layer > 0) { update_ctime(pvp, TRUE); } if (vp->v_back_layer == INVALID_LAYER && !must_set_wo) { /* * File doesn't exist in back -- throw away * the reference to it. */ free_vnode(vp); return (0); } if (vp->v_back_layer == UNKNOWN_LAYER) { return (remove_or_whiteout_file(pvp, vp, layer, must_set_wo, is_directory, wo_listp, wo_status)); } else if (vp->v_back_whited_out) { vp->v_layer = vp->v_back_layer; vp->v_back_layer = UNKNOWN_LAYER; vp->v_back_whited_out = FALSE; } else if (IS_WRITEABLE(vp) && *wo_status != WO_SET && *wo_status != WO_FAILED) { if (result = set_whiteout(pvp, vp, wo_listp)) { *wo_status = WO_FAILED; } else { *wo_status = WO_SET; } } } else { int old_layer; /* * vp->v_layer > layer (can happen if a file is removed which * is showing through from a read-only layer.) */ update_ctime(pvp, TRUE); old_layer = vp->v_layer; vp->v_layer = layer; if (IS_WRITEABLE(vp) && *wo_status != WO_SET && *wo_status != WO_FAILED) { if (result = set_whiteout(pvp, vp, wo_listp)) { *wo_status = WO_FAILED; } else { *wo_status = WO_SET; } } if (result == 0 && *wo_status != WO_FAILED) { vp->v_back_layer = old_layer; vp->v_back_whited_out = FALSE; } else { vp->v_layer = old_layer; } } if (result == 0 && *wo_status != WO_FAILED) { vp->v_whited_out = TRUE; if (vp->v_pnode != NULL) { release_pnodes(vp); } /* * Set v_dir_valid to FALSE in case this was a dir vnode * (it may be unwhited-out in the future, in which case we * don't want it to appear to be a valid directory.) */ vp->v_dir_valid = FALSE; } return (result);}/* * Clear the entry for file with vnode 'vp' in the directory 'pvp' at layer * 'layer', and allow the back instance of the file to show through. If * there is a whiteout entry for the file, clear it. */static intdir_clear_file(pvp, vp, layer, wo_status) struct vnode *pvp; struct vnode *vp; int layer; Whiteout_status *wo_status;{ int result = 0; if (*wo_status == WO_FAILED) { return (0); } if (vp->v_layer == layer) { if (!vp->v_whited_out && vp->v_layer > 0) { update_ctime(pvp, TRUE); } if (IS_WRITEABLE(vp) && vp->v_whited_out && *wo_status != WO_CLEARED && *wo_status != WO_FAILED) { if (result = unwhiteout(pvp, vp)) { *wo_status = WO_FAILED; } else { *wo_status = WO_CLEARED; } } if (*wo_status == WO_FAILED) { return (result); } if (vp->v_back_layer == UNKNOWN_LAYER) { pvp->v_dir_valid = FALSE; } else { /* * v_back_layer may be INVALID_LAYER here -- don't * release the vnode so that tfs_push will work */ vp->v_layer = vp->v_back_layer; vp->v_whited_out = vp->v_back_whited_out; vp->v_back_layer = UNKNOWN_LAYER; vp->v_back_whited_out = FALSE; } vp->v_dir_valid = FALSE; if (vp->v_pnode != NULL && result == 0) { release_pnodes(vp); } } else if (vp->v_layer < layer) { /* * if vp->v_back_layer < layer, do nothing; * vp->v_back_layer > layer impossible */ if (vp->v_back_layer == layer) { vp->v_back_layer = UNKNOWN_LAYER; vp->v_back_whited_out = FALSE; } } /* * vp->v_layer > layer impossible, unless this routine called twice * on same file */ return (result);}/* * This routine is called when a file has been removed and we don't know * whether or not the name exists in another layer further back. This can * happen when a directory is removed, because more than one layer is * removed. We can only keep track of two layers for a file with v_layer & * v_back_layer, so when the second layer is removed, the parent directory * needs to be revalidated before we can determine whether or not a * whiteout entry needs to be created. */static intremove_or_whiteout_file(pvp, vp, layer, must_set_wo, is_directory, wo_listp, wo_status) struct vnode *pvp; struct vnode *vp; int layer; bool_t must_set_wo; bool_t is_directory; Nse_whiteout *wo_listp; Whiteout_status *wo_status;{ struct pnode *pp; int result; switch (*wo_status) { case WO_SET: vp->v_layer = layer; vp->v_whited_out = TRUE; if (vp->v_pnode != NULL) { release_pnodes(vp); } if (CHILD_VNODE(vp) != NULL) { discard_child_vnodes(vp); } return (0); case WO_NOT_SET: vnode_tree_release(vp); return (0); case WO_FAILED: return (0); default: /* * Make sure that the pnode at 'layer' is not freed * by validate_directory as it is being held by * update_directory. */ pp = get_pnode_at_layer(pvp, layer); pp->p_refcnt++; pvp->v_dir_valid = FALSE; result = validate_directory(pvp); pp->p_refcnt--; if (result) { return (result); } if (vp->v_layer == INVALID_LAYER) { vnode_tree_release(vp); *wo_status = WO_NOT_SET; return (0); } else { /* vp->v_layer > layer */ return (dir_remove_file(pvp, vp, layer, must_set_wo, is_directory, wo_listp, wo_status)); } }}/* * The pnode for 'pvp' at layer 'layer' has been changed to 'newp'. */static voiddir_forward(pvp, layer, newp) struct vnode *pvp; int layer; struct pnode *newp;{ struct pnode *pp; struct pnode *prev_pp; struct pnode *next_pp; prev_pp = get_pnode_at_layer(pvp, (unsigned) layer - 1); pp = release_linknode(pvp, prev_pp); set_next_pnode(pvp, prev_pp, newp, layer - 1); next_pp = release_linknode(pvp, pp); free_pnode(pp); set_next_pnode(pvp, newp, next_pp, layer); newp->p_refcnt++;}/* * Transfer directory pnodes from vnode 'old_vp' to vnode 'new_vp'. * ('old_vp' may have been freed.) */static voidmove_pnodes(pp, old_vp, new_vp) struct pnode *pp; struct vnode *old_vp; struct vnode *new_vp;{ struct pnode *next_pp; int layer = 0; if (!has_linknode(old_vp, pp)) { return; } while (pp) { next_pp = release_linknode(old_vp, pp); set_next_pnode(new_vp, pp, next_pp, layer); pp = next_pp; layer++; }}/* * Returns vnode pointing to pnode pp which is under the same mountpt as vnode * pvp. Needed for rename when the source and destination directories are * not the same. */static struct vnode *vnode_of_pnode(pp, pvp) struct pnode *pp; struct vnode *pvp;{ struct vnode *rootvp; struct vnode *vp2; struct linknode *lp; rootvp = root_vnode_of(pvp); lp = pp->p_link; while (lp != NULL) { vp2 = lp->l_vnode; if (vp2->v_environ_id == pvp->v_environ_id && root_vnode_of(vp2) == rootvp) { return (vp2); } lp = lp->l_next; } return (NULL);}static struct vnode *root_vnode_of(vp) struct vnode *vp;{ while (vp != NULL && !vp->v_is_mount_pt) { vp = PARENT_VNODE(vp); } return (vp);}static voiddiscard_child_vnodes(pvp) struct vnode *pvp;{ struct vnode *vp; struct vnode *nextvp; for (vp = CHILD_VNODE(pvp); vp != NULL; vp = nextvp) { nextvp = NEXT_VNODE(vp); vnode_tree_release(vp); }}static voidclear_update_flags(pp) struct pnode *pp;{ struct linknode *lp; for (lp = pp->p_link; lp != NULL; lp = lp->l_next) { lp->l_vnode->v_pnode->p_updated = FALSE; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -