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 /libglusterfs/src/inode.c | |
| 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
Diffstat (limited to 'libglusterfs/src/inode.c')
| -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)  | 
