From: Gao Xiang Date: Tue, 9 Oct 2018 14:07:13 +0000 (+0800) Subject: staging: erofs: harden inode lookup for 32-bit platforms X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=2abd7814138774eb56319e9dcc0abd08ece45424;p=linux.git staging: erofs: harden inode lookup for 32-bit platforms This patch introduces inode hash function, test and set callbacks, and iget5_locked to find the right inode for 32-bit platforms. Reviewed-by: Chao Yu Signed-off-by: Gao Xiang Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/erofs/inode.c b/drivers/staging/erofs/inode.c index da8693a7c3d34..04c61a9d7b766 100644 --- a/drivers/staging/erofs/inode.c +++ b/drivers/staging/erofs/inode.c @@ -232,10 +232,45 @@ out_unlock: return err; } +/* + * erofs nid is 64bits, but i_ino is 'unsigned long', therefore + * we should do more for 32-bit platform to find the right inode. + */ +#if BITS_PER_LONG == 32 +static int erofs_ilookup_test_actor(struct inode *inode, void *opaque) +{ + const erofs_nid_t nid = *(erofs_nid_t *)opaque; + + return EROFS_V(inode)->nid == nid; +} + +static int erofs_iget_set_actor(struct inode *inode, void *opaque) +{ + const erofs_nid_t nid = *(erofs_nid_t *)opaque; + + inode->i_ino = erofs_inode_hash(nid); + return 0; +} +#endif + +static inline struct inode *erofs_iget_locked(struct super_block *sb, + erofs_nid_t nid) +{ + const unsigned long hashval = erofs_inode_hash(nid); + +#if BITS_PER_LONG >= 64 + /* it is safe to use iget_locked for >= 64-bit platform */ + return iget_locked(sb, hashval); +#else + return iget5_locked(sb, hashval, erofs_ilookup_test_actor, + erofs_iget_set_actor, &nid); +#endif +} + struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid, bool isdir) { - struct inode *inode = iget_locked(sb, nid); + struct inode *inode = erofs_iget_locked(sb, nid); if (unlikely(inode == NULL)) return ERR_PTR(-ENOMEM); diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index 5096b27bcf0d4..57575c7f56355 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -517,6 +517,15 @@ erofs_get_inline_page(struct inode *inode, } /* inode.c */ +static inline unsigned long erofs_inode_hash(erofs_nid_t nid) +{ +#if BITS_PER_LONG == 32 + return (nid >> 32) ^ (nid & 0xffffffff); +#else + return nid; +#endif +} + extern struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid, bool dir);