[Libsysio-commit] unification: libsysio/src inode.c
Brought to you by:
lward
From: Lee W. <lw...@us...> - 2007-04-11 20:44:20
|
Update of /cvsroot/libsysio/libsysio/src In directory sc8-pr-cvs6.sourceforge.net:/tmp/cvs-serv25129/src Modified Files: Tag: unification inode.c Log Message: _sysio_p_gone no longer automagically kills the base path node. This to get around a problem where if a mount fails the driver expects to be responsible for cleaning up it's own mess. Disconnects are now "real" in that all aliases for a base node have their parent pointers set to NULL. _sysio_pb_disconnect no longer disconnects the path node. Instead, it removes the name from the names cache, smashes the name in the node, and sets the parent of all the aliases to NULL. _sysio_pb_disconnect is now private to this file. _sysio_p_validate will fail to validate a NULL path node or one that has no parent -- Supporting the "real" disconnects. A new routine, _sysio_pb_pathof, returns an int and will discriminate a failure. The _sysio_pb_path routine remains but is deprecated. It still returns an empty string when encountering disconnected nodes. New routines, _sysio_p_unlink, _sysio_p_rmdir, and _sysio_p_rename, support appropriate operations and manipulate the namespace graph accordingly. Index: inode.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/inode.c,v retrieving revision 1.25.2.1 retrieving revision 1.25.2.2 diff -u -w -b -B -p -r1.25.2.1 -r1.25.2.2 --- inode.c 5 Feb 2007 15:54:27 -0000 1.25.2.1 +++ inode.c 11 Apr 2007 20:44:14 -0000 1.25.2.2 @@ -344,19 +344,13 @@ p_reclaim() t = max_names / 2; do { pno = next; - if (pno->p_ref) { - next = pno->p_nodes.tqe_next; - continue; - } - pno->p_ref++; - assert(pno->p_ref); - (void )_sysio_p_prune(pno); next = pno->p_nodes.tqe_next; - assert(pno->p_ref); - pno->p_ref--; if (pno->p_ref) continue; + next->p_ref++; + assert(next->p_ref); (void )_sysio_p_prune(pno); + next->p_ref--; } while (n_names > t && next); if (n_names > t) @@ -537,39 +532,16 @@ _sysio_p_new_alias(struct pnode *parent, 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); } /* - * Disconnect name referenced by the given path node from our reflection of - * the graph. - */ -void -_sysio_pb_disconnect(struct pnode_base *pb) -{ - /* - * We can't really do this. Callers aren't prepared to have - * path nodes disappear out from underneath. Then, there might be - * referenced aliases. Instead, we arrange things so that the - * referenced path-base node will never be found by the graph - * search routines again. - */ - pb->pb_parent = pb; -} - -/* * (Re)Validate passed path node. */ int @@ -578,6 +550,9 @@ _sysio_p_validate(struct pnode *pno, str struct inode *ino; int err; + if (!(pno && pno->p_parent)) + return -ENOENT; + ino = pno->p_base->pb_ino; err = PNOP_LOOKUP(pno, &ino, intnt, path); if (!err) { @@ -595,21 +570,12 @@ _sysio_p_validate(struct pnode *pno, str I_RELE(ino); } } - if (err && pno->p_base->pb_ino) { - /* - * Something has gone wrong with a valid path-base node. We - * need to disconnect the underlying path-base node from the - * tree. Setting the hash value of the name to zero will - * cause the graph search routines to ignore the node. - */ - _sysio_pb_disconnect(pno->p_base); - } 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. + * really -- This is a "lookup". Returned path node is referenced. */ int _sysio_p_find_alias(struct pnode *parent, @@ -676,6 +642,7 @@ _sysio_p_find_alias(struct pnode *parent return err; } +#if 0 /* * Prune idle path base nodes from the passed sub-tree, including the root. */ @@ -699,6 +666,7 @@ _sysio_prune(struct pnode_base *rpb) return; _sysio_pb_gone(rpb); } +#endif /* * Prune idle nodes from the passed sub-tree, including the root. @@ -718,10 +686,12 @@ _sysio_p_prune(struct pnode *root) while ((pb = nxtpb)) { nxtpb = pb->pb_sibs.le_next; nxtpno = pb->pb_aliases.lh_first; +#if 0 if (!nxtpno) { _sysio_prune(pb); continue; } +#endif while ((pno = nxtpno)) { nxtpno = pno->p_links.le_next; if (pno->p_mount != root->p_mount) { @@ -766,6 +736,9 @@ _sysio_p_prune(struct pnode *root) #endif } _sysio_p_gone(pno); + if (!(pb->pb_aliases.lh_first || + pb->pb_children.lh_first)) + _sysio_pb_gone(pb); } } @@ -773,7 +746,9 @@ _sysio_p_prune(struct pnode *root) /* * Can't get the root or we disconnect the sub-trees. */ - return count + (root->p_ref ? 1 : 0); + if (root->p_ref) + count++; + return count; } /* @@ -787,7 +762,7 @@ _sysio_p_prune(struct pnode *root) #else /* * This is an automount-point. Must - * unmount before relcaim. + * unmount before reclaim. */ P_REF(root); if (_sysio_do_unmount(root->p_mount) != 0) { @@ -795,8 +770,13 @@ _sysio_p_prune(struct pnode *root) count++; } #endif - } else + } else { + pb = root->p_base; _sysio_p_gone(root); + if (!(pb->pb_aliases.lh_first || + pb->pb_children.lh_first)) + _sysio_pb_gone(pb); + } return count; } @@ -808,8 +788,8 @@ _sysio_p_prune(struct pnode *root) * 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) +int +_sysio_pb_pathof(struct pnode_base *pb, const char separator, char **pathp) { size_t len, n; struct pnode_base *tmp; @@ -828,21 +808,17 @@ _sysio_pb_path(struct pnode_base *pb, co if (n) len++; tmp = tmp->pb_parent; - } while (tmp && tmp != tmp->pb_parent); + } while (tmp); + if (tmp && !tmp->pb_name.len) + return -ENOENT; if (!len) len++; - if (tmp && tmp->pb_parent == tmp) - len = 0; /* * Alloc space. */ buf = malloc(len + 1); if (!buf) - return NULL; - if (tmp && tmp->pb_parent == tmp) { - buf[0] = '\0'; - return buf; - } + return -ENOMEM; /* * Fill in the path buffer -- Backwards, since we're starting * from the end. @@ -862,14 +838,38 @@ _sysio_pb_path(struct pnode_base *pb, co tmp = tmp->pb_parent; } while (tmp); - return buf; + *pathp = buf; + return 0; +} + +/* + * Return path tracked by the base path node ancestor chain. + * + * NB: Deprecated. + */ +char * +_sysio_pb_path(struct pnode_base *pb, const char separator) +{ + int err; + char *path; + + err = _sysio_pb_pathof(pb, separator, &path); + if (err) { + if (err == -ENOMEM) + return NULL; + path = malloc(1); + if (path == NULL) + return NULL; + *path = '\0'; + } + return path; } /* * Common set attributes routine. */ int -_sysio_setattr(struct pnode *pno, +_sysio_p_setattr(struct pnode *pno, unsigned mask, struct intnl_stat *stbuf) { @@ -885,6 +885,165 @@ _sysio_setattr(struct pnode *pno, } /* + * Clean up the namespace graph after an unlink. + */ +static void +_sysio_pb_disconnect(struct pnode_base *pb) +{ + struct pnode *pno; + + /* + * Disconnect all aliases associated with the referenced base node. + */ + pno = pb->pb_aliases.lh_first; + do { + pno->p_parent = NULL; + } while ((pno = pno->p_links.le_next)); + /* + * Remove name from the names cache so that it can't + * be found anymore. + */ + if (pb->pb_name.len) + LIST_REMOVE(pb, pb_names); + pb->pb_name.len = 0; +} + +/* + * Perform unlink operation on some pnode. + */ +int +_sysio_p_unlink(struct pnode *pno) +{ + int err; + + if (!pno->p_base->pb_ino) + return -ENOENT; /* huh? */ + if (S_ISDIR(pno->p_base->pb_ino->i_stbuf.st_mode)) + return -EISDIR; + /* + * Call the FS implementation. + */ + err = PNOP_UNLINK(pno); + if (err) + return err; + /* + * Clean the namespace graphs to reflect the unlink. + */ + _sysio_pb_disconnect(pno->p_base); + return 0; +} + +/* + * Perform unlink operation on some pnode. + */ +int +_sysio_p_rmdir(struct pnode *pno) +{ + int err; + + if (!pno->p_base->pb_ino) + return -ENOENT; /* huh? */ + if (!S_ISDIR(pno->p_base->pb_ino->i_stbuf.st_mode)) + return -ENOTDIR; + /* + * Don't allow unlink of a root or a mount point. + */ + if (pno->p_cover || pno->p_mount->mnt_root == pno) + return -EBUSY; + /* + * Call the FS implementation. + */ + err = PNOP_RMDIR(pno); + if (err) + return err; + /* + * Clean the namespace graphs to reflect the unlink. + */ + _sysio_pb_disconnect(pno->p_base); + return 0; +} + +int +_sysio_p_rename(struct pnode *old, struct pnode *new) +{ + struct pnode_base *nxtpb, *pb; + int err; + + /* + * Check for rename to self. + */ + if (old == new) + return 0; + + /* + * No xdev renames please. + */ + if (old->p_mount->mnt_fs != new->p_mount->mnt_fs) + return -EXDEV; + + /* + * Don't allow mount points to move. + */ + if (old->p_mount->mnt_root == old || + old->p_cover || + new->p_mount->mnt_root == new) + return -EBUSY; + + /* + * Make sure the old pnode can't be found in the ancestor chain + * for the new. If it can, they are trying to move into a subdirectory + * of the old. + */ + nxtpb = new->p_base; + do { + pb = nxtpb; + nxtpb = pb->pb_parent; + if (pb == old->p_base) + return -EINVAL; + } while (nxtpb); + + if (new->p_base->pb_ino) { + /* + * Existing entry. We're replacing the new. Make sure that's + * ok. + */ + if (S_ISDIR(new->p_base->pb_ino->i_stbuf.st_mode)) { + if (!S_ISDIR(old->p_base->pb_ino->i_stbuf.st_mode)) + return -EISDIR; + /* + * Should check that the directory is empty. We + * can't reliably depend on any check we can make + * from here, though. + * + * We can check if anything is open in the sub-tree + * though. + */ + if (_sysio_p_prune(new) != 1) + return -EBUSY; + } else if (S_ISDIR(old->p_base->pb_ino->i_stbuf.st_mode)) + return -ENOTDIR; + } + + /* + * Give the op a try. + */ + err = PNOP_RENAME(old, new); + if (err) + return err; + /* + * Disconnect the old. + */ + _sysio_pb_disconnect(old->p_base); + /* + * Discionnect the new if positive. We want new lookups + * to find the just renamed entity. + */ + if (new->p_base->pb_ino) + _sysio_pb_disconnect(new->p_base); + return 0; +} + +/* * Do nothing. */ void |