diff options
author | Anand Avati <avati@gluster.com> | 2010-11-23 10:35:56 +0000 |
---|---|---|
committer | Anand V. Avati <avati@dev.gluster.com> | 2010-11-24 00:33:41 -0800 |
commit | 0ccd9f4f2ddf83d35cfa9bbc872ca84f6fb9c8a9 (patch) | |
tree | 3b6a341513844fa4f065c8e0cfd98b8cf31905e5 | |
parent | 7f68e386132af9e02bf37a3b4d0653de000bdefe (diff) |
inode: catch loop formation during inode_link() and fail linking
- explores all parent branches
- performs loop formation check only if the operation is resulting in relinking
of an inode already existing in the table
Signed-off-by: Anand V. Avati <avati@amp.gluster.com>
Signed-off-by: Anand V. Avati <avati@blackhole.gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 971 (dynamic volume management)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=971
-rw-r--r-- | libglusterfs/src/inode.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/libglusterfs/src/inode.c b/libglusterfs/src/inode.c index 57a3c35df2a..7ce3e5b95f5 100644 --- a/libglusterfs/src/inode.c +++ b/libglusterfs/src/inode.c @@ -152,6 +152,75 @@ __dentry_unset (dentry_t *dentry) } +static int +__foreach_ancestor_dentry (dentry_t *dentry, + int (per_dentry_fn) (dentry_t *dentry, + void *data), + void *data) +{ + inode_t *parent = NULL; + dentry_t *each = NULL; + int ret = 0; + + if (!dentry) + return 0; + + ret = per_dentry_fn (dentry, data); + if (ret) + goto out; + + parent = dentry->parent; + if (!parent) + goto out; + + list_for_each_entry (each, &parent->dentry_list, inode_list) { + ret = __foreach_ancestor_dentry (each, per_dentry_fn, data); + if (ret) + goto out; + } +out: + return ret; +} + + +static int +__check_cycle (dentry_t *a_dentry, void *data) +{ + inode_t *link_inode = NULL; + + link_inode = data; + + if (a_dentry->parent == link_inode) + return 1; + + return 0; +} + + +static int +__is_dentry_cyclic (dentry_t *dentry) +{ + int ret = 0; + inode_t *inode = NULL; + char uuidbuf[64]; + char *name = "<nul>"; + + ret = __foreach_ancestor_dentry (dentry, __check_cycle, + dentry->inode); + if (ret) { + if (dentry->name) + name = dentry->name; + uuid_unparse (inode->gfid, uuidbuf); + + gf_log (dentry->inode->table->name, GF_LOG_CRITICAL, + "detected cyclic loop formation during inode linkage.", + " inode (%"PRId64"/%s) linking under itself as %s", + inode->ino, uuidbuf, name); + } + + return ret; +} + static void __inode_unhash (inode_t *inode) @@ -674,6 +743,10 @@ __inode_link (inode_t *inode, inode_t *parent, const char *name, if (!old_dentry || old_dentry->inode != link_inode) { dentry = __dentry_create (link_inode, parent, name); + if (old_inode && __is_dentry_cyclic (dentry)) { + __dentry_unset (dentry); + return NULL; + } __dentry_hash (dentry); if (old_dentry) |