diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c index 672eed8b591326..283909b17db604 100644 --- a/fs/aufs/iinfo.c +++ b/fs/aufs/iinfo.c @@ -167,6 +167,7 @@ void au_icntnr_init_once(void *_c) spin_lock_init(&iinfo->ii_generation.ig_spin); au_rw_init(&iinfo->ii_rwsem); inode_init_once(&c->vfs_inode); + spin_lock_init(&c->nlink_spin); } void au_hinode_init(struct au_hinode *hinode) diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h index 56aa0186dc4af3..6824a768939259 100644 --- a/fs/aufs/inode.h +++ b/fs/aufs/inode.h @@ -13,6 +13,7 @@ #ifdef __KERNEL__ #include +#include "fstype.h" #include "rwsem.h" struct vfsmount; @@ -67,6 +68,7 @@ struct au_iinfo { struct au_icntnr { struct au_iinfo iinfo; struct inode vfs_inode; + spinlock_t nlink_spin; /* protects vfs_inode.i_nlink */ struct hlist_bl_node plink; struct rcu_head rcu; } ____cacheline_aligned_in_smp; @@ -112,6 +114,24 @@ static inline struct au_iinfo *au_ii(struct inode *inode) return &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); } +static inline void au_nlink_lock(struct inode *inode) +{ + spinlock_t *spin; + + AuDebugOn(!au_test_aufs(inode->i_sb)); + AuDebugOn(is_bad_inode(inode)); + spin = &(container_of(inode, struct au_icntnr, vfs_inode)->nlink_spin); + spin_lock(spin); +} + +static inline void au_nlink_unlock(struct inode *inode) +{ + spinlock_t *spin; + + spin = &(container_of(inode, struct au_icntnr, vfs_inode)->nlink_spin); + spin_unlock(spin); +} + /* ---------------------------------------------------------------------- */ /* inode.c */ diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c index 42aea4826211e5..86912a537c603f 100644 --- a/fs/aufs/vfsub.c +++ b/fs/aufs/vfsub.c @@ -38,6 +38,52 @@ int vfsub_sync_filesystem(struct super_block *h_sb) /* ---------------------------------------------------------------------- */ +unsigned int vfsub_inode_nlink_aufs(struct inode *inode) +{ + unsigned int nlink; + + au_nlink_lock(inode); + nlink = inode->i_nlink; + au_nlink_unlock(inode); + + return nlink; +} + +void vfsub_inc_nlink(struct inode *inode) +{ + au_nlink_lock(inode); + inc_nlink(inode); + au_nlink_unlock(inode); +} + +void vfsub_drop_nlink(struct inode *inode) +{ + au_nlink_lock(inode); + AuDebugOn(!inode->i_nlink); + drop_nlink(inode); + au_nlink_unlock(inode); +} + +void vfsub_clear_nlink(struct inode *inode) +{ + au_nlink_lock(inode); + AuDebugOn(!inode->i_nlink); + clear_nlink(inode); + au_nlink_unlock(inode); +} + +void vfsub_set_nlink(struct inode *inode, unsigned int nlink) +{ + /* + * stop setting the value equal to the current one, in order to stop + * a useless warning from vfs:destroy_inode() about sb->s_remove_count. + */ + au_nlink_lock(inode); + if (nlink != inode->i_nlink) + set_nlink(inode, nlink); + au_nlink_unlock(inode); +} + int vfsub_update_h_iattr(struct path *h_path, int *did) { int err; diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h index 4eea10d3f2d6c3..bf12e73cf4a6d1 100644 --- a/fs/aufs/vfsub.h +++ b/fs/aufs/vfsub.h @@ -17,6 +17,7 @@ #include #include #include "debug.h" +#include "fstype.h" /* copied from linux/fs/internal.h */ /* todo: BAD approach!! */ @@ -44,28 +45,50 @@ enum { /* ---------------------------------------------------------------------- */ -static inline void au_set_nlink(struct inode *inode, unsigned int nlink) +unsigned int vfsub_inode_nlink_aufs(struct inode *inode); + +enum au_inode_type { + AU_I_AUFS, + AU_I_BRANCH, + AU_I_UNKNOWN +}; + +static inline unsigned int vfsub_inode_nlink(struct inode *inode, + enum au_inode_type type) { - /* - * stop setting the value equal to the current one, in order to stop - * a useless warning from vfs:destroy_inode() about sb->s_remove_count. - */ - if (nlink != inode->i_nlink) - set_nlink(inode, nlink); + unsigned int nlink; + + switch (type) { + case AU_I_AUFS: + nlink = vfsub_inode_nlink_aufs(inode); + break; + case AU_I_BRANCH: /* aufs cannot be a branch of another aufs mount */ + AuDebugOn(au_test_aufs(inode->i_sb)); + nlink = inode->i_nlink; + break; + case AU_I_UNKNOWN: + if (au_test_aufs(inode->i_sb)) + nlink = vfsub_inode_nlink_aufs(inode); + else + nlink = inode->i_nlink; + break; + }; + + return nlink; } -static inline void au_init_nlink(struct inode *inode, unsigned int nlink) +void vfsub_inc_nlink(struct inode *inode); +void vfsub_drop_nlink(struct inode *inode); +void vfsub_clear_nlink(struct inode *inode); +void vfsub_set_nlink(struct inode *inode, unsigned int nlink); + +static inline void vfsub_inode_nlink_init(struct inode *inode, + unsigned int nlink) { /* to ignore sb->s_remove_count, do not use set_nlink() */ inode->__i_nlink = nlink; } -static inline void vfsub_drop_nlink(struct inode *inode) -{ - AuDebugOn(!inode->i_nlink); - drop_nlink(inode); -} - static inline void vfsub_dead_dir(struct inode *inode) { AuDebugOn(!S_ISDIR(inode->i_mode));