📄 inode.c
字号:
#ifdef ZERO_SUM_MEMORY/* * Shutdown */void_sysio_i_shutdown(){ struct pnodes_block *pnblk; while ((pnblk = pnblocks.lh_first)) { LIST_REMOVE(pnblk, pnblk_links); free(pnblk); }}#endif/* * Allocate, initialize and establish appropriate links for new path (alias) * node. */struct pnode *_sysio_p_new_alias(struct pnode *parent, struct pnode_base *pb, struct mount *mnt){ struct pnode *pno; assert(!pb->pb_name.name || pb->pb_name.hashval); pno = free_pnodes.lh_first; if (!pno) { more_pnodes(); pno = free_pnodes.lh_first; } if (!pno) return NULL; LIST_REMOVE(pno, p_links); pno->p_ref = 1; pno->p_parent = parent; if (!pno->p_parent) pno->p_parent = pno; pno->p_base = pb; pno->p_mount = mnt; pno->p_cover = NULL; LIST_INSERT_HEAD(&pb->pb_aliases, pno, p_links); TAILQ_INSERT_TAIL(&_sysio_pnodes, pno, p_nodes); return pno;}/* * For reclamation of idle path (alias) node. */void_sysio_p_gone(struct pnode *pno){ struct pnode_base *pb; assert(!pno->p_ref); assert(!pno->p_cover); TAILQ_REMOVE(&_sysio_pnodes, pno, p_nodes); LIST_REMOVE(pno, p_links); pb = pno->p_base; if (!(pb->pb_aliases.lh_first || pb->pb_children.lh_first)) _sysio_pb_gone(pb); LIST_INSERT_HEAD(&free_pnodes, pno, p_links);}/* * (Re)Validate passed path node. */int_sysio_p_validate(struct pnode *pno, struct intent *intnt, const char *path){ struct inode *ino; struct pnode_base *rootpb; int err; ino = pno->p_base->pb_ino; /* * An invalid pnode will not have an associated inode. We'll use * the FS root inode, then -- It *must* be valid. */ rootpb = pno->p_mount->mnt_root->p_base; assert(rootpb->pb_ino); err = rootpb->pb_ino->i_ops.inop_lookup(pno, &ino, intnt, path); /* * If the inode lookup returns a different inode, release the old if * present and point to the new. */ if (err || pno->p_base->pb_ino != ino) { if (pno->p_base->pb_ino) I_RELE(pno->p_base->pb_ino); pno->p_base->pb_ino = ino; } return err;}/* * Find (or create!) an alias for the given parent and name. A misnomer, * really -- This is a "get". Returned path node is referenced. */int_sysio_p_find_alias(struct pnode *parent, struct qstr *name, struct pnode **pnop){ struct pnode_base *pb; int err; struct pnode *pno; /* * Find the named child. */ if (name->len) { /* * Try the names table. */ pb = names[name->hashval % NAMES_TABLE_LEN].lh_first; while (pb) { if (pb->pb_parent == parent->p_base && pb->pb_name.len == name->len && strncmp(pb->pb_name.name, name->name, name->len) == 0) break; pb = pb->pb_names.le_next; } } else { /* * Brute force through the parent's list of children. */ pb = parent->p_base->pb_children.lh_first; while (pb) { if (pb->pb_parent == parent->p_base && pb->pb_name.len == name->len && strncmp(pb->pb_name.name, name->name, name->len) == 0) break; pb = pb->pb_sibs.le_next; } } if (!pb) { /* * None found, create new child. */ pb = _sysio_pb_new(name, parent->p_base, NULL); if (!pb) return -ENOMEM; } /* * Now find the proper alias. It's the one with the passed * parent. */ err = 0; pno = pb->pb_aliases.lh_first; while (pno) { if (pno->p_parent == parent) { P_REF(pno); break; } pno = pno->p_links.le_next; } if (!pno) { /* * Hmm. No alias. Just create an invalid one, to be * validated later. */ pno = _sysio_p_new_alias(parent, pb, parent->p_mount); if (!pno) err = -ENOMEM; } if (!err) *pnop = pno; return err;}/* * Prune idle path base nodes freom the passed sub-tree, including the root. */static void_sysio_prune(struct pnode_base *rpb){ struct pnode_base *nxtpb, *pb; nxtpb = rpb->pb_children.lh_first; while ((pb = nxtpb)) { nxtpb = pb->pb_sibs.le_next; if (pb->pb_aliases.lh_first) continue; if (pb->pb_children.lh_first) { _sysio_prune(pb); continue; } _sysio_pb_gone(pb); } if (rpb->pb_children.lh_first) return; _sysio_pb_gone(rpb);}/* * Prune idle nodes from the passed sub-tree, including the root. * * Returns the number of aliases on the same mount that could not be pruned. * i.e. a zero return means the entire sub-tree is gone. */size_t_sysio_p_prune(struct pnode *root){ size_t count; struct pnode_base *nxtpb, *pb; struct pnode *nxtpno, *pno; count = 0; nxtpb = root->p_base->pb_children.lh_first; while ((pb = nxtpb)) { nxtpb = pb->pb_sibs.le_next; nxtpno = pb->pb_aliases.lh_first; if (!nxtpno) { _sysio_prune(pb); continue; } while ((pno = nxtpno)) { nxtpno = pno->p_links.le_next; if (pno->p_mount != root->p_mount) { /* * Not the alias we were looking for. */ continue; } if (pno->p_base->pb_children.lh_first) { /* * Node is interior. Recurse. */ count += _sysio_p_prune(pno); continue; } if (pno->p_ref) { /* * Can't prune; It's active. */ count++; continue; } assert(!pno->p_cover); /* covered => ref'd! */ assert(!pno->p_base->pb_name.name || pno->p_base->pb_name.hashval); /* * Ok to prune. */ if (pno->p_mount->mnt_root == pno) {#ifndef AUTOMOUNT_FILE_NAME count++; continue;#else /* * This is an automount-point. Must * unmount before relcaim. */ P_REF(pno); if (_sysio_do_unmount(pno->p_mount) != 0) { P_RELE(pno); count++; } continue;#endif } _sysio_p_gone(pno); } } if (count) { /* * Can't get the root or we disconnect the sub-trees. */ return count + (root->p_ref ? 1 : 0); } /* * All that is left is the root. Try for it too. */ if (root->p_ref) { count++; } else if (root->p_mount->mnt_root == root) {#ifndef AUTOMOUNT_FILE_NAME count++;#else /* * This is an automount-point. Must * unmount before relcaim. */ P_REF(root); if (_sysio_do_unmount(root->p_mount) != 0) { P_RELE(root); count++; }#endif } else _sysio_p_gone(root); return count;}/* * Return path tracked by the base path node ancestor chain. * * Remember, base path nodes track the path relative to the file system and * path (alias) nodes track path relative to our name space -- They cross * mount points. */char *_sysio_pb_path(struct pnode_base *pb, const char separator){ char *buf; size_t len, n; struct pnode_base *tmp; char *cp; /* * First pass: Traverse to the root of the sub-tree, remembering * lengths. */ len = 0; tmp = pb; do { n = tmp->pb_name.len; len += tmp->pb_name.len; if (n) len++; tmp = tmp->pb_parent; } while (tmp); if (!len) len++; /* * Alloc space. */ buf = malloc(len + 1); if (!buf) return NULL; /* * Fill in the path buffer -- Backwards, since we're starting * from the end. */ cp = buf; *cp = separator; cp += len; *cp = '\0'; /* NUL term */ tmp = pb; do { cp -= tmp->pb_name.len; n = tmp->pb_name.len; if (n) { (void )strncpy(cp, tmp->pb_name.name, n); *--cp = separator; } tmp = tmp->pb_parent; } while (tmp); return buf;}/* * Common set attributes routine. */int_sysio_setattr(struct pnode *pno, struct inode *ino, unsigned mask, struct intnl_stat *stbuf){ /* * It is possible that pno is null (for ftruncate call). */ if (pno) assert(!ino || pno->p_base->pb_ino == ino); if (!ino) ino = pno->p_base->pb_ino; assert(ino); if (pno && IS_RDONLY(pno)) return -EROFS; /* * Determining permission to change the attributes is * difficult, at best. Just try it. */ return (*ino->i_ops.inop_setattr)(pno, ino, mask, stbuf);}/* * Do nothing. */void_sysio_do_noop(){ return;}/* * Abort. */void_sysio_do_illop(){ abort();}/* * Return -EBADF */int_sysio_do_ebadf(){ return -EBADF;}/* * Return -EINVAL */int_sysio_do_einval(){ return -EINVAL;}/* * Return -ENOENT */int_sysio_do_enoent(){ return -ENOENT;}/* * Return -ESPIPE */int_sysio_do_espipe(){ return -ESPIPE;}/* * Return -EISDIR */int_sysio_do_eisdir(){ return -EISDIR;}/* * Return -ENOSYS */int_sysio_do_enosys(){ return -ENOSYS;}/* * Return -ENODEV */int_sysio_do_enodev(){ return -ENODEV;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -