2007-10-10 21:45:36

by David Howells

[permalink] [raw]
Subject: [PATCH 00/31] Remove iget() and read_inode() [try #3]



Hi Christoph, Al,

Here's a set of patches that remove all calls to iget() and all read_inode()
functions. They should be removed for two reasons: firstly they don't lend
themselves to good error handling, and secondly their presence is a temptation
for code outside a filesystem to call iget() to access inodes within that
filesystem.

There are a few benefits to this:

(1) Error handling gets simpler as you can return an error code rather than
having to call is_bad_inode().

(2) You can now tell the difference between ENOMEM and EIO occurring in the
read_inode() path.

(3) The code should get smaller. iget() is an inline function that is
typically called 2-3 times per filesystem that uses it. By folding the
iget code into the read_inode code for each filesystem, it eliminates
some duplication.

A tarball of the patches can be retrieved from:

http://people.redhat.com/~dhowells/iget-remove.tar.bz2


Additionally, there are a couple of patches that introduce an ERR_CAST() macro
to be used instead of ERR_PTR(PTR_ERR(p)) constructs and apply it to all such
instances in the kernel.

Of the patches directly relevant to the subject:

The first patch adds a function, iget_failed() that is a canned piece of code
for killing an inode when the inode construction path fails.

The second and third patches makes AFS and GFS2 use iget_failed() rather than
interpolating the sequence directly.

The fourth patch marks iget() and read_inode() as being deprecated.

The final patch removes iget() and read_inode() completely.

Each of the other patches modify a filesystem that used iget() and read_inode()
to use iget_locked() instead. The standard procedure was to convert:

void thingyfs_read_inode(struct inode *inode)
{
...
}

into:

struct inode *thingyfs_iget(struct super_block *sp, unsigned long ino)
{
struct inode *inode;
int ret;

inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW))
return inode;

...
unlock_new_inode(inode);
return inode;
error:
iget_failed(inode);
return ERR_PTR(ret);
}

and then call thingyfs_iget() rather than iget():

ret = -EINVAL;
inode = iget(sb, ino);
if (!inode || is_bad_inode(inode))
goto error;

becomes:

inode = thingyfs_iget(sb, ino);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
goto error;
}

There were exceptions; most notably it appeared FAT should be calling ilookup()
not iget().

Additionally, HPPFS and HOSTFS (UM-specific filesystems) really need checking:

hostfs_kern.c:

(*) hostfs_iget() should perhaps subsume init_inode() and hostfs_read_inode().

(*) It would appear that all hostfs inodes are the same inode because iget()
was being called with inode number 0 - which forms the lookup key.

hppfs_kern.c:

(*) The HPPFS inode retains a pointer to the proc dentry it is shadowing, but
whilst it does appear to retain a reference to it, it doesn't appear to
destroy the reference if the inode goes away.

(*) hppfs_iget() should perhaps subsume init_inode() and hppfs_read_inode().

(*) It would appear that all hppfs inodes are the same inode because iget()
was being called with inode number 0, which forms the lookup key.

In addition to the introduction of ERR_CAST, the ext2, ext3 and ext4 patches
have been fixed from Jan Kara's review.

David


2007-10-10 21:43:44

by David Howells

[permalink] [raw]
Subject: [PATCH 01/31] Add an ERR_CAST() macro to complement ERR_PTR and co. [try #3]

Add an ERR_CAST() macro to complement ERR_PTR and co. for the purposes of
casting an error entyped as one pointer type to an error of another pointer
type whilst making it explicit as to what is going on.

This provides a replacement for the ERR_PTR(PTR_ERR(p)) construct.

Signed-off-by: David Howells <[email protected]>
---

include/linux/err.h | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/include/linux/err.h b/include/linux/err.h
index 1ab1d44..08409cd 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -34,6 +34,18 @@ static inline long IS_ERR(const void *ptr)
return IS_ERR_VALUE((unsigned long)ptr);
}

+/**
+ * ERR_CAST - Explicitly cast an error-valued pointer to another pointer type
+ * @ptr: The pointer to cast.
+ *
+ * Explicitly cast an error-valued pointer to another pointer type in such a
+ * way as to make it clear that's what's going on.
+ */
+static inline void *ERR_CAST(const void *ptr)
+{
+ return (void *) ptr;
+}
+
#endif

#endif /* _LINUX_ERR_H */

2007-10-10 21:44:01

by David Howells

[permalink] [raw]
Subject: [PATCH 02/31] Convert ERR_PTR(PTR_ERR(p)) instances to ERR_CAST(p) [try #3]

Convert instances of ERR_PTR(PTR_ERR(p)) to ERR_CAST(p) using:

perl -spi -e 's/ERR_PTR[(]PTR_ERR[(](.*)[)][)]/ERR_CAST(\1)/' `grep -rl 'ERR_PTR[(]*PTR_ERR' fs crypto net security`

Signed-off-by: David Howells <[email protected]>
---

crypto/cbc.c | 2 +-
crypto/cryptd.c | 4 ++--
crypto/ecb.c | 2 +-
crypto/hmac.c | 2 +-
crypto/lrw.c | 2 +-
crypto/pcbc.c | 2 +-
crypto/xcbc.c | 4 ++--
fs/9p/vfs_inode.c | 2 +-
fs/affs/namei.c | 2 +-
fs/afs/dir.c | 4 ++--
fs/afs/security.c | 2 +-
fs/fat/inode.c | 2 +-
fs/fuse/dir.c | 6 +++---
fs/gfs2/dir.c | 2 +-
fs/gfs2/ops_export.c | 2 +-
fs/gfs2/ops_inode.c | 2 +-
fs/jffs2/write.c | 4 ++--
fs/nfs/getroot.c | 8 ++++----
fs/nfsd/export.c | 4 ++--
fs/quota.c | 4 ++--
fs/reiserfs/inode.c | 2 +-
fs/reiserfs/xattr.c | 6 +++---
fs/vfat/namei.c | 2 +-
net/rxrpc/af_rxrpc.c | 6 +++---
security/keys/key.c | 2 +-
security/keys/process_keys.c | 2 +-
security/keys/request_key.c | 4 ++--
security/keys/request_key_auth.c | 2 +-
28 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/crypto/cbc.c b/crypto/cbc.c
index 1f2649e..ea39ba2 100644
--- a/crypto/cbc.c
+++ b/crypto/cbc.c
@@ -288,7 +288,7 @@ static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);

inst = crypto_alloc_instance("cbc", alg);
if (IS_ERR(inst))
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index ac6dce2..7dc0c5d 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -229,7 +229,7 @@ static struct crypto_instance *cryptd_alloc_blkcipher(
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);

inst = cryptd_alloc_instance(alg, state);
if (IS_ERR(inst))
@@ -266,7 +266,7 @@ static struct crypto_instance *cryptd_alloc(struct rtattr **tb)

algt = crypto_get_attr_type(tb);
if (IS_ERR(algt))
- return ERR_PTR(PTR_ERR(algt));
+ return ERR_CAST(algt);

switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) {
case CRYPTO_ALG_TYPE_BLKCIPHER:
diff --git a/crypto/ecb.c b/crypto/ecb.c
index 6310387..a46838e 100644
--- a/crypto/ecb.c
+++ b/crypto/ecb.c
@@ -128,7 +128,7 @@ static struct crypto_instance *crypto_ecb_alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);

inst = crypto_alloc_instance("ecb", alg);
if (IS_ERR(inst))
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 8802fb6..bed9e25 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -210,7 +210,7 @@ static struct crypto_instance *hmac_alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
CRYPTO_ALG_TYPE_HASH_MASK);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);

inst = crypto_alloc_instance("hmac", alg);
if (IS_ERR(inst))
diff --git a/crypto/lrw.c b/crypto/lrw.c
index 621095d..9d52e58 100644
--- a/crypto/lrw.c
+++ b/crypto/lrw.c
@@ -241,7 +241,7 @@ static struct crypto_instance *alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);

inst = crypto_alloc_instance("lrw", alg);
if (IS_ERR(inst))
diff --git a/crypto/pcbc.c b/crypto/pcbc.c
index c3ed8a1..c04f52a 100644
--- a/crypto/pcbc.c
+++ b/crypto/pcbc.c
@@ -292,7 +292,7 @@ static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);

inst = crypto_alloc_instance("pcbc", alg);
if (IS_ERR(inst))
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index 9f502b8..da018c1 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -301,13 +301,13 @@ static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);

switch(alg->cra_blocksize) {
case 16:
break;
default:
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);
}

inst = crypto_alloc_instance("xcbc", alg);
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index e5c45ee..53444f0 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -568,7 +568,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
v9ses = v9fs_inode2v9ses(dir);
dfid = v9fs_fid_lookup(dentry->d_parent);
if (IS_ERR(dfid))
- return ERR_PTR(PTR_ERR(dfid));
+ return ERR_CAST(dfid);

name = (char *) dentry->d_name.name;
fid = p9_client_walk(dfid, 1, &name, 1);
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index a42143c..b407e9e 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -209,7 +209,7 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
bh = affs_find_entry(dir, dentry);
affs_unlock_dir(dir);
if (IS_ERR(bh)) {
- return ERR_PTR(PTR_ERR(bh));
+ return ERR_CAST(bh);
}
if (bh) {
u32 ino = bh->b_blocknr;
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 33fe39a..f861d08 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -512,7 +512,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
key = afs_request_key(vnode->volume->cell);
if (IS_ERR(key)) {
_leave(" = %ld [key]", PTR_ERR(key));
- return ERR_PTR(PTR_ERR(key));
+ return ERR_CAST(key);
}

ret = afs_validate(vnode, key);
@@ -540,7 +540,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
key_put(key);
if (IS_ERR(inode)) {
_leave(" = %ld", PTR_ERR(inode));
- return ERR_PTR(PTR_ERR(inode));
+ return ERR_CAST(inode);
}

dentry->d_op = &afs_fs_dentry_operations;
diff --git a/fs/afs/security.c b/fs/afs/security.c
index 566fe71..9446a1f 100644
--- a/fs/afs/security.c
+++ b/fs/afs/security.c
@@ -95,7 +95,7 @@ static struct afs_vnode *afs_get_auth_inode(struct afs_vnode *vnode,
auth_inode = afs_iget(vnode->vfs_inode.i_sb, key,
&vnode->status.parent, NULL, NULL);
if (IS_ERR(auth_inode))
- return ERR_PTR(PTR_ERR(auth_inode));
+ return ERR_CAST(auth_inode);
}

auth_vnode = AFS_FS_I(auth_inode);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 4baa5f2..960ed3d 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -764,7 +764,7 @@ static struct dentry *fat_get_parent(struct dentry *child)
inode = fat_build_inode(child->d_sb, de, i_pos);
brelse(bh);
if (IS_ERR(inode)) {
- parent = ERR_PTR(PTR_ERR(inode));
+ parent = ERR_CAST(inode);
goto out;
}
parent = d_alloc_anon(inode);
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index bd5a772..69ce097 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -234,12 +234,12 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,

req = fuse_get_req(fc);
if (IS_ERR(req))
- return ERR_PTR(PTR_ERR(req));
+ return ERR_CAST(req);

forget_req = fuse_get_req(fc);
if (IS_ERR(forget_req)) {
fuse_put_request(fc, req);
- return ERR_PTR(PTR_ERR(forget_req));
+ return ERR_CAST(forget_req);
}

fuse_lookup_init(req, dir, entry, &outarg);
@@ -897,7 +897,7 @@ static char *read_link(struct dentry *dentry)
char *link;

if (IS_ERR(req))
- return ERR_PTR(PTR_ERR(req));
+ return ERR_CAST(req);

link = (char *) __get_free_page(GFP_KERNEL);
if (!link) {
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 2beb2f4..7c7b437 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1497,7 +1497,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name)
dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);
if (dent) {
if (IS_ERR(dent))
- return ERR_PTR(PTR_ERR(dent));
+ return ERR_CAST(dent);
inode = gfs2_inode_lookup(dir->i_sb,
be16_to_cpu(dent->de_type),
be64_to_cpu(dent->de_inum.no_addr),
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
index b8312ed..549c35d 100644
--- a/fs/gfs2/ops_export.c
+++ b/fs/gfs2/ops_export.c
@@ -177,7 +177,7 @@ static struct dentry *gfs2_get_parent(struct dentry *child)
* have to return that as a(n invalid) pointer to dentry.
*/
if (IS_ERR(inode))
- return ERR_PTR(PTR_ERR(inode));
+ return ERR_CAST(inode);

dentry = d_alloc_anon(inode);
if (!dentry) {
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 911c115..c49d3d8 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -111,7 +111,7 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,

inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
if (inode && IS_ERR(inode))
- return ERR_PTR(PTR_ERR(inode));
+ return ERR_CAST(inode);

if (inode)
return d_splice_alias(inode, dentry);
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 664c164..6daf299 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -177,7 +177,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
void *hold_err = fn->raw;
/* Release the full_dnode which is now useless, and return */
jffs2_free_full_dnode(fn);
- return ERR_PTR(PTR_ERR(hold_err));
+ return ERR_CAST(hold_err);
}
fn->ofs = je32_to_cpu(ri->offset);
fn->size = je32_to_cpu(ri->dsize);
@@ -302,7 +302,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
void *hold_err = fd->raw;
/* Release the full_dirent which is now useless, and return */
jffs2_free_full_dirent(fd);
- return ERR_PTR(PTR_ERR(hold_err));
+ return ERR_CAST(hold_err);
}

if (retried) {
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 522e5ad..93d1479 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -70,7 +70,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)

iroot = nfs_fhget(sb, &dummyfh, &fattr);
if (IS_ERR(iroot))
- return ERR_PTR(PTR_ERR(iroot));
+ return ERR_CAST(iroot);

root = d_alloc_root(iroot);
if (!root) {
@@ -93,7 +93,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
if (IS_ERR(inode)) {
dprintk("nfs_get_root: get root inode failed\n");
- return ERR_PTR(PTR_ERR(inode));
+ return ERR_CAST(inode);
}

/* root dentries normally start off anonymous and get spliced in later
@@ -257,7 +257,7 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)

iroot = nfs_fhget(sb, &dummyfh, &fattr);
if (IS_ERR(iroot))
- return ERR_PTR(PTR_ERR(iroot));
+ return ERR_CAST(iroot);

root = d_alloc_root(iroot);
if (!root) {
@@ -286,7 +286,7 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
inode = nfs_fhget(sb, mntfh, &fattr);
if (IS_ERR(inode)) {
dprintk("nfs_get_root: get root inode failed\n");
- return ERR_PTR(PTR_ERR(inode));
+ return ERR_CAST(inode);
}

/* root dentries normally start off anonymous and get spliced in later
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index cba899a..9feaec6 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1221,13 +1221,13 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
struct svc_export *exp;
struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
if (IS_ERR(ek))
- return ERR_PTR(PTR_ERR(ek));
+ return ERR_CAST(ek);

exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
cache_put(&ek->h, &svc_expkey_cache);

if (IS_ERR(exp))
- return ERR_PTR(PTR_ERR(exp));
+ return ERR_CAST(exp);
return exp;
}

diff --git a/fs/quota.c b/fs/quota.c
index 99b24b5..84f28dd 100644
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -341,11 +341,11 @@ static inline struct super_block *quotactl_block(const char __user *special)
char *tmp = getname(special);

if (IS_ERR(tmp))
- return ERR_PTR(PTR_ERR(tmp));
+ return ERR_CAST(tmp);
bdev = lookup_bdev(tmp);
putname(tmp);
if (IS_ERR(bdev))
- return ERR_PTR(PTR_ERR(bdev));
+ return ERR_CAST(bdev);
sb = get_super(bdev);
bdput(bdev);
if (!sb)
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index ddde489..496fbe3 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1534,7 +1534,7 @@ struct dentry *reiserfs_get_dentry(struct super_block *sb, void *vobjp)
if (!inode)
inode = ERR_PTR(-ESTALE);
if (IS_ERR(inode))
- return ERR_PTR(PTR_ERR(inode));
+ return ERR_CAST(inode);
result = d_alloc_anon(inode);
if (!result) {
iput(inode);
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index bf6e582..624ddd4 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -155,7 +155,7 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode,

xadir = open_xa_dir(inode, flags);
if (IS_ERR(xadir)) {
- return ERR_PTR(PTR_ERR(xadir));
+ return ERR_CAST(xadir);
} else if (xadir && !xadir->d_inode) {
dput(xadir);
return ERR_PTR(-ENODATA);
@@ -164,7 +164,7 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode,
xafile = lookup_one_len(name, xadir, strlen(name));
if (IS_ERR(xafile)) {
dput(xadir);
- return ERR_PTR(PTR_ERR(xafile));
+ return ERR_CAST(xafile);
}

if (xafile->d_inode) { /* file exists */
@@ -203,7 +203,7 @@ static struct file *open_xa_file(const struct inode *inode, const char *name,

xafile = get_xa_file_dentry(inode, name, flags);
if (IS_ERR(xafile))
- return ERR_PTR(PTR_ERR(xafile));
+ return ERR_CAST(xafile);
else if (!xafile->d_inode) {
dput(xafile);
return ERR_PTR(-ENODATA);
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index c28add2..cd450be 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -705,7 +705,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
brelse(sinfo.bh);
if (IS_ERR(inode)) {
unlock_kernel();
- return ERR_PTR(PTR_ERR(inode));
+ return ERR_CAST(inode);
}
alias = d_find_alias(inode);
if (alias) {
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index c58fa0d..1549ac2 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -237,7 +237,7 @@ static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock,
/* find a remote transport endpoint from the local one */
peer = rxrpc_get_peer(srx, gfp);
if (IS_ERR(peer))
- return ERR_PTR(PTR_ERR(peer));
+ return ERR_CAST(peer);

/* find a transport */
trans = rxrpc_get_transport(rx->local, peer, gfp);
@@ -280,7 +280,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
trans = rxrpc_name_to_transport(sock, (struct sockaddr *) srx,
sizeof(*srx), 0, gfp);
if (IS_ERR(trans)) {
- call = ERR_PTR(PTR_ERR(trans));
+ call = ERR_CAST(trans);
trans = NULL;
goto out;
}
@@ -304,7 +304,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,

bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp);
if (IS_ERR(bundle)) {
- call = ERR_PTR(PTR_ERR(bundle));
+ call = ERR_CAST(bundle);
goto out;
}

diff --git a/security/keys/key.c b/security/keys/key.c
index 01bbc6d..abe9245 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -820,7 +820,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key = key_alloc(ktype, description, current->fsuid, current->fsgid,
current, perm, flags);
if (IS_ERR(key)) {
- key_ref = ERR_PTR(PTR_ERR(key));
+ key_ref = ERR_CAST(key);
goto error_3;
}

diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index b6f8680..67c1341 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -660,7 +660,7 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,

key = key_lookup(id);
if (IS_ERR(key)) {
- key_ref = ERR_PTR(PTR_ERR(key));
+ key_ref = ERR_CAST(key);
goto error;
}

diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 5575001..9251e6a 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -418,7 +418,7 @@ struct key *request_key_and_link(struct key_type *type,
key = key_ref_to_ptr(key_ref);
}
else if (PTR_ERR(key_ref) != -EAGAIN) {
- key = ERR_PTR(PTR_ERR(key_ref));
+ key = ERR_CAST(key_ref);
}
else {
/* the search failed, but the keyrings were searchable, so we
@@ -458,7 +458,7 @@ struct key *request_key_and_link(struct key_type *type,
}

if (PTR_ERR(key_ref) != -EAGAIN) {
- key = ERR_PTR(PTR_ERR(key_ref));
+ key = ERR_CAST(key_ref);
break;
}
}
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index cbf58a9..fcfe408 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -252,7 +252,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
current);

if (IS_ERR(authkey_ref)) {
- authkey = ERR_PTR(PTR_ERR(authkey_ref));
+ authkey = ERR_CAST(authkey_ref);
goto error;
}


2007-10-10 21:44:38

by David Howells

[permalink] [raw]
Subject: [PATCH 03/31] IGET: Introduce a function to register iget failure [try #3]

Introduce a function to register failure in an inode construction path. This
includes marking the inode under construction as bad, unlocking it and
releasing it.

Signed-off-by: David Howells <[email protected]>
---

Documentation/filesystems/porting | 18 +++++++++++++-----
fs/bad_inode.c | 14 ++++++++++++++
include/linux/fs.h | 1 +
3 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index dac45c9..3b0fb22 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -184,11 +184,19 @@ just takes the superblock and inode number as arguments and does the
test and set for you.

e.g.
- inode = iget_locked(sb, ino);
- if (inode->i_state & I_NEW) {
- read_inode_from_disk(inode);
- unlock_new_inode(inode);
- }
+ inode = iget_locked(sb, ino);
+ if (inode->i_state & I_NEW) {
+ err = read_inode_from_disk(inode);
+ if (err < 0) {
+ iget_failed(inode);
+ return err;
+ }
+ unlock_new_inode(inode);
+ }
+
+Note that if the process of setting up a new inode fails, then iget_failed()
+should be called on the inode to render it dead, and an appropriate error
+should be passed back to the caller.

---
[recommended]
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 521ff7c..f1c2ea8 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -359,3 +359,17 @@ int is_bad_inode(struct inode *inode)
}

EXPORT_SYMBOL(is_bad_inode);
+
+/**
+ * iget_failed - Mark an under-construction inode as dead and release it
+ * @inode: The inode to discard
+ *
+ * Mark an under-construction inode as dead and release it.
+ */
+void iget_failed(struct inode *inode)
+{
+ make_bad_inode(inode);
+ unlock_new_inode(inode);
+ iput(inode);
+}
+EXPORT_SYMBOL(iget_failed);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 16421f6..c24d433 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1631,6 +1631,7 @@ static inline struct inode *iget(struct super_block *sb, unsigned long ino)
}

extern void __iget(struct inode * inode);
+extern void iget_failed(struct inode *);
extern void clear_inode(struct inode *);
extern void destroy_inode(struct inode *);
extern struct inode *new_inode(struct super_block *);

2007-10-10 21:45:03

by David Howells

[permalink] [raw]
Subject: [PATCH 04/31] IGET: Use iget_failed() in AFS [try #3]

Use iget_failed() in AFS to kill a failed inode.

Signed-off-by: David Howells <[email protected]>
---

fs/afs/inode.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index d196840..ca9b02f 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -196,10 +196,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,

/* failure */
bad_inode:
- make_bad_inode(inode);
- unlock_new_inode(inode);
- iput(inode);
-
+ iget_failed(inode);
_leave(" = %d [bad]", ret);
return ERR_PTR(ret);
}

2007-10-10 21:46:23

by David Howells

[permalink] [raw]
Subject: [PATCH 05/31] IGET: Use iget_failed() in GFS2 [try #3]

Use iget_failed() in GFS2 to kill a failed inode.

Signed-off-by: David Howells <[email protected]>
---

fs/gfs2/inode.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 34f7bcd..498844f 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -185,7 +185,7 @@ fail_put:
ip->i_gl->gl_object = NULL;
gfs2_glock_put(ip->i_gl);
fail:
- iput(inode);
+ iget_failed(inode);
return ERR_PTR(error);
}


2007-10-10 21:46:36

by David Howells

[permalink] [raw]
Subject: [PATCH 06/31] IGET: Stop AFFS from using iget() and read_inode() [try #3]

Stop the AFFS filesystem from using iget() and read_inode(). Replace
affs_read_inode() with affs_iget(), and call that instead of iget().
affs_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

affs_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
---

fs/affs/affs.h | 2 +-
fs/affs/amigaffs.c | 6 ++++--
fs/affs/inode.c | 20 +++++++++++++-------
fs/affs/namei.c | 10 ++++------
fs/affs/super.c | 12 +++++++++---
5 files changed, 31 insertions(+), 19 deletions(-)

diff --git a/fs/affs/affs.h b/fs/affs/affs.h
index 232c694..0bce4ff 100644
--- a/fs/affs/affs.h
+++ b/fs/affs/affs.h
@@ -174,7 +174,7 @@ extern void affs_put_inode(struct inode *inode);
extern void affs_drop_inode(struct inode *inode);
extern void affs_delete_inode(struct inode *inode);
extern void affs_clear_inode(struct inode *inode);
-extern void affs_read_inode(struct inode *inode);
+extern struct inode *affs_iget(struct super_block *sb, unsigned long ino);
extern int affs_write_inode(struct inode *inode, int);
extern int affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type);

diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index f4de4b9..8055730 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -170,9 +170,11 @@ affs_remove_link(struct dentry *dentry)
if (!link_bh)
goto done;

- dir = iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
- if (!dir)
+ dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
+ if (IS_ERR(dir)) {
+ retval = PTR_ERR(dir);
goto done;
+ }

affs_lock_dir(dir);
affs_fix_dcache(dentry, link_ino);
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 4609a6c..edea76c 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -15,20 +15,25 @@
extern const struct inode_operations affs_symlink_inode_operations;
extern struct timezone sys_tz;

-void
-affs_read_inode(struct inode *inode)
+struct inode *affs_iget(struct super_block *sb, unsigned long ino)
{
- struct super_block *sb = inode->i_sb;
struct affs_sb_info *sbi = AFFS_SB(sb);
struct buffer_head *bh;
struct affs_head *head;
struct affs_tail *tail;
+ struct inode *inode;
u32 block;
u32 size;
u32 prot;
u16 id;

- pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ pr_debug("AFFS: affs_iget(%lu)\n",inode->i_ino);

block = inode->i_ino;
bh = affs_bread(sb, block);
@@ -154,12 +159,13 @@ affs_read_inode(struct inode *inode)
sys_tz.tz_minuteswest * 60;
inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0;
affs_brelse(bh);
- return;
+ unlock_new_inode(inode);
+ return inode;

bad_inode:
- make_bad_inode(inode);
affs_brelse(bh);
- return;
+ iget_failed(inode);
+ return ERR_PTR(-EIO);
}

int
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index b407e9e..2218f1e 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -208,9 +208,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
affs_lock_dir(dir);
bh = affs_find_entry(dir, dentry);
affs_unlock_dir(dir);
- if (IS_ERR(bh)) {
+ if (IS_ERR(bh))
return ERR_CAST(bh);
- }
if (bh) {
u32 ino = bh->b_blocknr;

@@ -223,10 +222,9 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
}
affs_brelse(bh);
- inode = iget(sb, ino);
- if (!inode) {
- return ERR_PTR(-EACCES);
- }
+ inode = affs_iget(sb, ino);
+ if (IS_ERR(inode))
+ return ERR_PTR(PTR_ERR(inode));
}
dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations;
d_add(dentry, inode);
diff --git a/fs/affs/super.c b/fs/affs/super.c
index c80191a..f005050 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -113,7 +113,6 @@ static void destroy_inodecache(void)
static const struct super_operations affs_sops = {
.alloc_inode = affs_alloc_inode,
.destroy_inode = affs_destroy_inode,
- .read_inode = affs_read_inode,
.write_inode = affs_write_inode,
.put_inode = affs_put_inode,
.drop_inode = affs_drop_inode,
@@ -271,6 +270,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
unsigned long mount_flags;
int tmp_flags; /* fix remount prototype... */
u8 sig[4];
+ int ret = -EINVAL;

pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");

@@ -444,7 +444,12 @@ got_root:

/* set up enough so that it can read an inode */

- root_inode = iget(sb, root_block);
+ root_inode = affs_iget(sb, root_block);
+ if (IS_ERR(root_inode)) {
+ ret = PTR_ERR(root_inode);
+ goto out_error_noinode;
+ }
+
sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root) {
printk(KERN_ERR "AFFS: Get root inode failed\n");
@@ -461,12 +466,13 @@ got_root:
out_error:
if (root_inode)
iput(root_inode);
+out_error_noinode:
kfree(sbi->s_bitmap);
affs_brelse(root_bh);
kfree(sbi->s_prefix);
kfree(sbi);
sb->s_fs_info = NULL;
- return -EINVAL;
+ return ret;
}

static int

2007-10-10 21:46:53

by David Howells

[permalink] [raw]
Subject: [PATCH 07/31] IGET: Stop autofs from using iget() and read_inode() [try #3]

Stop the autofs filesystem from using iget() and read_inode(). Replace
autofs_read_inode() with autofs_iget(), and call that instead of iget().
autofs_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

Signed-off-by: David Howells <[email protected]>
---

fs/autofs/autofs_i.h | 1 +
fs/autofs/inode.c | 27 ++++++++++++++++++---------
fs/autofs/root.c | 22 ++++++++++++++++++----
3 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index 8b4cca3..901a3e6 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -150,6 +150,7 @@ extern const struct file_operations autofs_root_operations;

int autofs_fill_super(struct super_block *, void *, int);
void autofs_kill_sb(struct super_block *sb);
+struct inode *autofs_iget(struct super_block *, unsigned long);

/* Queue management functions */

diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index e7204d7..fc6a15e 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -52,10 +52,7 @@ out_kill_sb:
kill_anon_super(sb);
}

-static void autofs_read_inode(struct inode *inode);
-
static const struct super_operations autofs_sops = {
- .read_inode = autofs_read_inode,
.statfs = simple_statfs,
};

@@ -164,7 +161,9 @@ int autofs_fill_super(struct super_block *s, void *data, int silent)
s->s_time_gran = 1;
sbi->sb = s;

- root_inode = iget(s, AUTOFS_ROOT_INO);
+ root_inode = autofs_iget(s, AUTOFS_ROOT_INO);
+ if (IS_ERR(root_inode))
+ goto fail_free;
root = d_alloc_root(root_inode);
pipe = NULL;

@@ -230,11 +229,17 @@ fail_unlock:
return -EINVAL;
}

-static void autofs_read_inode(struct inode *inode)
+struct inode *autofs_iget(struct super_block *sb, unsigned long ino)
{
- ino_t ino = inode->i_ino;
unsigned int n;
- struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);
+ struct autofs_sb_info *sbi = autofs_sbi(sb);
+ struct inode *inode;
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;

/* Initialize to the default case (stub directory) */

@@ -250,7 +255,7 @@ static void autofs_read_inode(struct inode *inode)
inode->i_op = &autofs_root_inode_operations;
inode->i_fop = &autofs_root_operations;
inode->i_uid = inode->i_gid = 0; /* Changed in read_super */
- return;
+ goto done;
}

inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
@@ -263,7 +268,7 @@ static void autofs_read_inode(struct inode *inode)
n = ino - AUTOFS_FIRST_SYMLINK;
if (n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) {
printk("autofs: Looking for bad symlink inode %u\n", (unsigned int) ino);
- return;
+ goto done;
}

inode->i_op = &autofs_symlink_inode_operations;
@@ -275,4 +280,8 @@ static void autofs_read_inode(struct inode *inode)
inode->i_size = sl->len;
inode->i_nlink = 1;
}
+
+done:
+ unlock_new_inode(inode);
+ return inode;
}
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index c148953..3aec567 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -114,8 +114,8 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
dentry->d_time = (unsigned long) ent;

if (!dentry->d_inode) {
- inode = iget(sb, ent->ino);
- if (!inode) {
+ inode = autofs_iget(sb, ent->ino);
+ if (IS_ERR(inode)) {
/* Failed, but leave pending for next time */
return 1;
}
@@ -274,6 +274,7 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
unsigned int n;
int slsize;
struct autofs_symlink *sl;
+ struct inode *inode;

DPRINTK(("autofs_root_symlink: %s <- ", symname));
autofs_say(dentry->d_name.name,dentry->d_name.len);
@@ -331,7 +332,12 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
ent->dentry = NULL; /* We don't keep the dentry for symlinks */

autofs_hash_insert(dh,ent);
- d_instantiate(dentry, iget(dir->i_sb,ent->ino));
+
+ inode = autofs_iget(dir->i_sb, ent->ino);
+ if (IS_ERR(inode))
+ return PTR_ERR(inode);
+
+ d_instantiate(dentry, inode);
unlock_kernel();
return 0;
}
@@ -428,6 +434,7 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
struct autofs_dirhash *dh = &sbi->dirhash;
struct autofs_dir_ent *ent;
+ struct inode *inode;
ino_t ino;

lock_kernel();
@@ -469,7 +476,14 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
autofs_hash_insert(dh,ent);

inc_nlink(dir);
- d_instantiate(dentry, iget(dir->i_sb,ino));
+
+ inode = autofs_iget(dir->i_sb, ino);
+ if (IS_ERR(inode)) {
+ drop_nlink(dir);
+ return PTR_ERR(inode);
+ }
+
+ d_instantiate(dentry, inode);
unlock_kernel();

return 0;

2007-10-10 21:47:22

by David Howells

[permalink] [raw]
Subject: [PATCH 08/31] IGET: Stop BEFS from using iget() and read_inode() [try #3]

Stop the BEFS filesystem from using iget() and read_inode(). Replace
befs_read_inode() with befs_iget(), and call that instead of iget().
befs_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

befs_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
Acked-by: Will Dyson <[email protected]>
---

fs/befs/linuxvfs.c | 39 +++++++++++++++++++++++++--------------
1 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index a451418..fd9866e 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -35,7 +35,7 @@ static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int);
static int befs_readpage(struct file *file, struct page *page);
static sector_t befs_bmap(struct address_space *mapping, sector_t block);
static struct dentry *befs_lookup(struct inode *, struct dentry *, struct nameidata *);
-static void befs_read_inode(struct inode *ino);
+static struct inode *befs_iget(struct super_block *, unsigned long);
static struct inode *befs_alloc_inode(struct super_block *sb);
static void befs_destroy_inode(struct inode *inode);
static int befs_init_inodecache(void);
@@ -52,7 +52,6 @@ static int befs_statfs(struct dentry *, struct kstatfs *);
static int parse_options(char *, befs_mount_options *);

static const struct super_operations befs_sops = {
- .read_inode = befs_read_inode, /* initialize & read inode */
.alloc_inode = befs_alloc_inode, /* allocate a new inode */
.destroy_inode = befs_destroy_inode, /* deallocate an inode */
.put_super = befs_put_super, /* uninit super */
@@ -198,9 +197,9 @@ befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
return ERR_PTR(-ENODATA);
}

- inode = iget(dir->i_sb, (ino_t) offset);
- if (!inode)
- return ERR_PTR(-EACCES);
+ inode = befs_iget(dir->i_sb, (ino_t) offset);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);

d_add(dentry, inode);

@@ -296,17 +295,23 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
inode_init_once(&bi->vfs_inode);
}

-static void
-befs_read_inode(struct inode *inode)
+static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
{
struct buffer_head *bh = NULL;
befs_inode *raw_inode = NULL;

- struct super_block *sb = inode->i_sb;
befs_sb_info *befs_sb = BEFS_SB(sb);
befs_inode_info *befs_ino = NULL;
+ struct inode *inode;
+ long ret = -EIO;

- befs_debug(sb, "---> befs_read_inode() " "inode = %lu", inode->i_ino);
+ befs_debug(sb, "---> befs_read_inode() " "inode = %lu", ino);
+
+ inode = iget_locked(sb, ino);
+ if (IS_ERR(inode))
+ return inode;
+ if (!(inode->i_state & I_NEW))
+ return inode;

befs_ino = BEFS_I(inode);

@@ -402,15 +407,16 @@ befs_read_inode(struct inode *inode)

brelse(bh);
befs_debug(sb, "<--- befs_read_inode()");
- return;
+ unlock_new_inode(inode);
+ return inode;

unacquire_bh:
brelse(bh);

unacquire_none:
- make_bad_inode(inode);
+ iget_failed(inode);
befs_debug(sb, "<--- befs_read_inode() - Bad inode");
- return;
+ return ERR_PTR(ret);
}

/* Initialize the inode cache. Called at fs setup.
@@ -752,6 +758,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
befs_sb_info *befs_sb;
befs_super_block *disk_sb;
struct inode *root;
+ long ret = -EINVAL;

const unsigned long sb_block = 0;
const off_t x86_sb_off = 512;
@@ -833,7 +840,11 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
/* Set real blocksize of fs */
sb_set_blocksize(sb, (ulong) befs_sb->block_size);
sb->s_op = (struct super_operations *) &befs_sops;
- root = iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)));
+ root = befs_iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)));
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
+ goto unacquire_priv_sbp;
+ }
sb->s_root = d_alloc_root(root);
if (!sb->s_root) {
iput(root);
@@ -868,7 +879,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent)

unacquire_none:
sb->s_fs_info = NULL;
- return -EINVAL;
+ return ret;
}

static int

2007-10-10 21:47:38

by David Howells

[permalink] [raw]
Subject: [PATCH 09/31] IGET: Stop BFS from using iget() and read_inode() [try #3]

Stop the BFS filesystem from using iget() and read_inode(). Replace
bfs_read_inode() with bfs_iget(), and call that instead of iget().
bfs_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

bfs_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
---

fs/bfs/bfs.h | 2 ++
fs/bfs/dir.c | 6 +++---
fs/bfs/inode.c | 32 ++++++++++++++++++++++----------
3 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h
index 130f6c6..5cf50d4 100644
--- a/fs/bfs/bfs.h
+++ b/fs/bfs/bfs.h
@@ -46,6 +46,8 @@ static inline struct bfs_inode_info *BFS_I(struct inode *inode)
#define printf(format, args...) \
printk(KERN_ERR "BFS-fs: %s(): " format, __FUNCTION__, ## args)

+/* inode.c */
+extern struct inode *bfs_iget(struct super_block *sb, unsigned long ino);

/* file.c */
extern const struct inode_operations bfs_file_inops;
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 097f149..03c8bdb 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -141,10 +141,10 @@ static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry, st
if (bh) {
unsigned long ino = (unsigned long)le16_to_cpu(de->ino);
brelse(bh);
- inode = iget(dir->i_sb, ino);
- if (!inode) {
+ inode = bfs_iget(dir->i_sb, ino);
+ if (IS_ERR(inode)) {
unlock_kernel();
- return ERR_PTR(-EACCES);
+ return ERR_CAST(inode);
}
}
unlock_kernel();
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index f346eb1..76798c9 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -32,25 +32,29 @@ MODULE_LICENSE("GPL");

void dump_imap(const char *prefix, struct super_block * s);

-static void bfs_read_inode(struct inode * inode)
+struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
{
- unsigned long ino = inode->i_ino;
struct bfs_inode * di;
struct buffer_head * bh;
+ struct inode *inode;
int block, off;

+ inode = iget_locked(sb, ino);
+ if (IS_ERR(inode))
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
if (ino < BFS_ROOT_INO || ino > BFS_SB(inode->i_sb)->si_lasti) {
printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino);
- make_bad_inode(inode);
- return;
+ goto error;
}

block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
bh = sb_bread(inode->i_sb, block);
if (!bh) {
printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id, ino);
- make_bad_inode(inode);
- return;
+ goto error;
}

off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
@@ -85,6 +89,12 @@ static void bfs_read_inode(struct inode * inode)
BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino); /* can be 0 so we store a copy */

brelse(bh);
+ unlock_new_inode(inode);
+ return inode;
+
+error:
+ iget_failed(inode);
+ return ERR_PTR(-EIO);
}

static int bfs_write_inode(struct inode * inode, int unused)
@@ -271,7 +281,6 @@ static void destroy_inodecache(void)
static const struct super_operations bfs_sops = {
.alloc_inode = bfs_alloc_inode,
.destroy_inode = bfs_destroy_inode,
- .read_inode = bfs_read_inode,
.write_inode = bfs_write_inode,
.delete_inode = bfs_delete_inode,
.put_super = bfs_put_super,
@@ -306,6 +315,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
struct inode * inode;
unsigned i, imap_len;
struct bfs_sb_info * info;
+ long ret = -EINVAL;

info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
@@ -340,14 +350,16 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
set_bit(i, info->si_imap);

s->s_op = &bfs_sops;
- inode = iget(s, BFS_ROOT_INO);
- if (!inode) {
+ inode = bfs_iget(s, BFS_ROOT_INO);
+ if (IS_ERR(inode)) {
+ ret = PTR_ERR(inode);
kfree(info->si_imap);
goto out;
}
s->s_root = d_alloc_root(inode);
if (!s->s_root) {
iput(inode);
+ ret = -ENOMEM;
kfree(info->si_imap);
goto out;
}
@@ -402,7 +414,7 @@ out:
brelse(bh);
kfree(info);
s->s_fs_info = NULL;
- return -EINVAL;
+ return ret;
}

static int bfs_get_sb(struct file_system_type *fs_type,

2007-10-10 21:47:53

by David Howells

[permalink] [raw]
Subject: [PATCH 10/31] IGET: Stop CIFS from using iget() and read_inode() [try #3]

Stop the CIFS filesystem from using iget() and read_inode(). Replace
cifs_read_inode() with cifs_iget(), and call that instead of iget().
cifs_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

cifs_read_super() now returns any error incurred when getting the root inode
instead of ENOMEM.

Signed-off-by: David Howells <[email protected]>
---

fs/cifs/cifsfs.c | 8 ++++----
fs/cifs/cifsfs.h | 1 +
fs/cifs/inode.c | 35 ++++++++++++++++++++++++++---------
3 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index cabb6a5..1cb13f5 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -126,10 +126,11 @@ cifs_read_super(struct super_block *sb, void *data,
#endif
sb->s_blocksize = CIFS_MAX_MSGSIZE;
sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */
- inode = iget(sb, ROOT_I);
+ inode = cifs_iget(sb, ROOT_I);

- if (!inode) {
- rc = -ENOMEM;
+ if (IS_ERR(inode)) {
+ rc = PTR_ERR(inode);
+ inode = NULL;
goto out_no_root;
}

@@ -481,7 +482,6 @@ static int cifs_remount(struct super_block *sb, int *flags, char *data)
}

static const struct super_operations cifs_super_ops = {
- .read_inode = cifs_read_inode,
.put_super = cifs_put_super,
.statfs = cifs_statfs,
.alloc_inode = cifs_alloc_inode,
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index a20de77..74a3190 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -43,6 +43,7 @@ extern void cifs_read_inode(struct inode *);

/* Functions related to inodes */
extern const struct inode_operations cifs_dir_inode_ops;
+extern struct inode *cifs_iget(struct super_block *, unsigned long);
extern int cifs_create(struct inode *, struct dentry *, int,
struct nameidata *);
extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index dd41677..48966b9 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -576,20 +576,37 @@ int cifs_get_inode_info(struct inode **pinode,
}

/* gets root inode */
-void cifs_read_inode(struct inode *inode)
+struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
{
int xid;
struct cifs_sb_info *cifs_sb;
+ struct inode *inode;
+ long ret;

- cifs_sb = CIFS_SB(inode->i_sb);
- xid = GetXid();
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (inode->i_state & I_NEW) {
+ cifs_sb = CIFS_SB(inode->i_sb);
+ xid = GetXid();

- if (cifs_sb->tcon->unix_ext)
- cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
- else
- cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid);
- /* can not call macro FreeXid here since in a void func */
- _FreeXid(xid);
+ if (cifs_sb->tcon->unix_ext)
+ ret = cifs_get_inode_info_unix(&inode, "", inode->i_sb,
+ xid);
+ else
+ ret = cifs_get_inode_info(&inode, "", NULL, inode->i_sb,
+ xid);
+ /* can not call macro FreeXid here since in a void func */
+ _FreeXid(xid);
+ if (ret < 0) {
+ iget_failed(inode);
+ inode = ERR_PTR(ret);
+ } else {
+ unlock_new_inode(inode);
+ }
+ }
+
+ return inode;
}

int cifs_unlink(struct inode *inode, struct dentry *direntry)

2007-10-10 21:48:13

by David Howells

[permalink] [raw]
Subject: [PATCH 11/31] IGET: Stop EFS from using iget() and read_inode() [try #3]

Stop the EFS filesystem from using iget() and read_inode(). Replace
efs_read_inode() with efs_iget(), and call that instead of iget().
efs_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

efs_fill_super() returns any error incurred when getting the root inode
instead of EACCES.

Signed-off-by: David Howells <[email protected]>
---

fs/efs/inode.c | 25 +++++++++++++++++--------
fs/efs/namei.c | 23 ++++++++++++-----------
fs/efs/super.c | 18 ++++++++++++------
include/linux/efs_fs.h | 2 +-
4 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/fs/efs/inode.c b/fs/efs/inode.c
index 174696f..627c302 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -45,17 +45,26 @@ static inline void extent_copy(efs_extent *src, efs_extent *dst) {
return;
}

-void efs_read_inode(struct inode *inode)
+struct inode *efs_iget(struct super_block *super, unsigned long ino)
{
int i, inode_index;
dev_t device;
u32 rdev;
struct buffer_head *bh;
- struct efs_sb_info *sb = SUPER_INFO(inode->i_sb);
- struct efs_inode_info *in = INODE_INFO(inode);
+ struct efs_sb_info *sb = SUPER_INFO(super);
+ struct efs_inode_info *in;
efs_block_t block, offset;
struct efs_dinode *efs_inode;
-
+ struct inode *inode;
+
+ inode = iget_locked(super, ino);
+ if (IS_ERR(inode))
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ in = INODE_INFO(inode);
+
/*
** EFS layout:
**
@@ -159,13 +168,13 @@ void efs_read_inode(struct inode *inode)
break;
}

- return;
+ unlock_new_inode(inode);
+ return inode;

read_inode_error:
printk(KERN_WARNING "EFS: failed to read inode %lu\n", inode->i_ino);
- make_bad_inode(inode);
-
- return;
+ iget_failed(inode);
+ return ERR_PTR(-EIO);
}

static inline efs_block_t
diff --git a/fs/efs/namei.c b/fs/efs/namei.c
index 5276b19..77d7106 100644
--- a/fs/efs/namei.c
+++ b/fs/efs/namei.c
@@ -64,9 +64,10 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei
lock_kernel();
inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
if (inodenum) {
- if (!(inode = iget(dir->i_sb, inodenum))) {
+ inode = efs_iget(dir->i_sb, inodenum);
+ if (IS_ERR(inode)) {
unlock_kernel();
- return ERR_PTR(-EACCES);
+ return ERR_CAST(inode);
}
}
unlock_kernel();
@@ -85,12 +86,11 @@ struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp)

if (ino == 0)
return ERR_PTR(-ESTALE);
- inode = iget(sb, ino);
- if (inode == NULL)
- return ERR_PTR(-ENOMEM);
+ inode = efs_iget(sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);

- if (is_bad_inode(inode) ||
- (generation && inode->i_generation != generation)) {
+ if (generation && inode->i_generation != generation) {
result = ERR_PTR(-ESTALE);
goto out_iput;
}
@@ -112,7 +112,7 @@ struct dentry *efs_get_parent(struct dentry *child)
struct dentry *parent;
struct inode *inode;
efs_ino_t ino;
- int error;
+ long error;

lock_kernel();

@@ -121,10 +121,11 @@ struct dentry *efs_get_parent(struct dentry *child)
if (!ino)
goto fail;

- error = -EACCES;
- inode = iget(child->d_inode->i_sb, ino);
- if (!inode)
+ inode = efs_iget(child->d_inode->i_sb, ino);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
goto fail;
+ }

error = -ENOMEM;
parent = d_alloc_anon(inode);
diff --git a/fs/efs/super.c b/fs/efs/super.c
index ce4acb8..685279d 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -107,7 +107,6 @@ static int efs_remount(struct super_block *sb, int *flags, char *data)
static const struct super_operations efs_superblock_operations = {
.alloc_inode = efs_alloc_inode,
.destroy_inode = efs_destroy_inode,
- .read_inode = efs_read_inode,
.put_super = efs_put_super,
.statfs = efs_statfs,
.remount_fs = efs_remount,
@@ -246,6 +245,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
struct efs_sb_info *sb;
struct buffer_head *bh;
struct inode *root;
+ int ret = -EINVAL;

sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
if (!sb)
@@ -302,12 +302,18 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
}
s->s_op = &efs_superblock_operations;
s->s_export_op = &efs_export_ops;
- root = iget(s, EFS_ROOTINODE);
- s->s_root = d_alloc_root(root);
-
- if (!(s->s_root)) {
+ root = efs_iget(s, EFS_ROOTINODE);
+ if (IS_ERR(root)) {
printk(KERN_ERR "EFS: get root inode failed\n");
+ ret = PTR_ERR(root);
+ goto out_no_fs;
+ }
+
+ s->s_root = d_alloc_root(root);
+ if (!(s->s_root)) {
+ printk(KERN_ERR "EFS: get root dentry failed\n");
iput(root);
+ ret = -ENOMEM;
goto out_no_fs;
}

@@ -317,7 +323,7 @@ out_no_fs_ul:
out_no_fs:
s->s_fs_info = NULL;
kfree(sb);
- return -EINVAL;
+ return ret;
}

static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h
index 16cb25c..18b725f 100644
--- a/include/linux/efs_fs.h
+++ b/include/linux/efs_fs.h
@@ -40,7 +40,7 @@ extern const struct inode_operations efs_dir_inode_operations;
extern const struct file_operations efs_dir_operations;
extern const struct address_space_operations efs_symlink_aops;

-extern void efs_read_inode(struct inode *);
+extern struct inode *efs_iget(struct super_block *, unsigned long);
extern efs_block_t efs_map_block(struct inode *, efs_block_t);
extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);


2007-10-10 21:48:33

by David Howells

[permalink] [raw]
Subject: [PATCH 12/31] IGET: Stop EXT2 from using iget() and read_inode() [try #3]

Stop the EXT2 filesystem from using iget() and read_inode(). Replace
ext2_read_inode() with ext2_iget(), and call that instead of iget().
ext2_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

ext2_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
Acked-by: "Theodore Ts'o" <[email protected]>
---

fs/ext2/ext2.h | 2 +-
fs/ext2/inode.c | 30 ++++++++++++++++++++++--------
fs/ext2/namei.c | 12 ++++++------
fs/ext2/super.c | 32 ++++++++++++++++++--------------
4 files changed, 47 insertions(+), 29 deletions(-)

diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 9fd0ec5..85ca3de 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -123,7 +123,7 @@ extern void ext2_check_inodes_bitmap (struct super_block *);
extern unsigned long ext2_count_free (struct buffer_head *, unsigned);

/* inode.c */
-extern void ext2_read_inode (struct inode *);
+extern struct inode *ext2_iget (struct super_block *, unsigned long);
extern int ext2_write_inode (struct inode *, int);
extern void ext2_put_inode (struct inode *);
extern void ext2_delete_inode (struct inode *);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 0079b2c..fa5e115 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1074,20 +1074,32 @@ void ext2_get_inode_flags(struct ext2_inode_info *ei)
ei->i_flags |= EXT2_DIRSYNC_FL;
}

-void ext2_read_inode (struct inode * inode)
+struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
{
- struct ext2_inode_info *ei = EXT2_I(inode);
- ino_t ino = inode->i_ino;
+ struct ext2_inode_info *ei;
struct buffer_head * bh;
- struct ext2_inode * raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);
+ struct ext2_inode * raw_inode;
+ struct inode *inode;
+ long ret = -EIO;
int n;

+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ ei = EXT2_I(inode);
#ifdef CONFIG_EXT2_FS_POSIX_ACL
ei->i_acl = EXT2_ACL_NOT_CACHED;
ei->i_default_acl = EXT2_ACL_NOT_CACHED;
#endif
- if (IS_ERR(raw_inode))
+
+ raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);
+ if (IS_ERR(raw_inode)) {
+ ret = PTR_ERR(raw_inode);
goto bad_inode;
+ }

inode->i_mode = le16_to_cpu(raw_inode->i_mode);
inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
@@ -1111,6 +1123,7 @@ void ext2_read_inode (struct inode * inode)
if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) {
/* this inode is deleted */
brelse (bh);
+ ret = -ESTALE;
goto bad_inode;
}
inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
@@ -1180,11 +1193,12 @@ void ext2_read_inode (struct inode * inode)
}
brelse (bh);
ext2_set_inode_flags(inode);
- return;
+ unlock_new_inode(inode);
+ return inode;

bad_inode:
- make_bad_inode(inode);
- return;
+ iget_failed(inode);
+ return ERR_PTR(ret);
}

static int ext2_update_inode(struct inode * inode, int do_sync)
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index e69beed..80c97fd 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -63,9 +63,9 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
ino = ext2_inode_by_name(dir, dentry);
inode = NULL;
if (ino) {
- inode = iget(dir->i_sb, ino);
- if (!inode)
- return ERR_PTR(-EACCES);
+ inode = ext2_iget(dir->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
}
return d_splice_alias(inode, dentry);
}
@@ -83,10 +83,10 @@ struct dentry *ext2_get_parent(struct dentry *child)
ino = ext2_inode_by_name(child->d_inode, &dotdot);
if (!ino)
return ERR_PTR(-ENOENT);
- inode = iget(child->d_inode->i_sb, ino);
+ inode = ext2_iget(child->d_inode->i_sb, ino);

- if (!inode)
- return ERR_PTR(-EACCES);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
parent = d_alloc_anon(inode);
if (!parent) {
iput(inode);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 639a32c..33e8b29 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -232,7 +232,6 @@ static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *da
static const struct super_operations ext2_sops = {
.alloc_inode = ext2_alloc_inode,
.destroy_inode = ext2_destroy_inode,
- .read_inode = ext2_read_inode,
.write_inode = ext2_write_inode,
.put_inode = ext2_put_inode,
.delete_inode = ext2_delete_inode,
@@ -266,11 +265,10 @@ static struct dentry *ext2_get_dentry(struct super_block *sb, void *vobjp)
* it might be "neater" to call ext2_get_inode first and check
* if the inode is valid.....
*/
- inode = iget(sb, ino);
- if (inode == NULL)
- return ERR_PTR(-ENOMEM);
- if (is_bad_inode(inode) ||
- (generation && inode->i_generation != generation)) {
+ inode = ext2_iget(sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
+ if (generation && inode->i_generation != generation) {
/* we didn't find the right inode.. */
iput(inode);
return ERR_PTR(-ESTALE);
@@ -649,6 +647,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
unsigned long logic_sb_block;
unsigned long offset = 0;
unsigned long def_mount_opts;
+ long ret = -EINVAL;
int blocksize = BLOCK_SIZE;
int db_count;
int i, j;
@@ -918,19 +917,24 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
sb->s_op = &ext2_sops;
sb->s_export_op = &ext2_export_ops;
sb->s_xattr = ext2_xattr_handlers;
- root = iget(sb, EXT2_ROOT_INO);
- sb->s_root = d_alloc_root(root);
- if (!sb->s_root) {
- iput(root);
- printk(KERN_ERR "EXT2-fs: get root inode failed\n");
+ root = ext2_iget(sb, EXT2_ROOT_INO);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
goto failed_mount3;
}
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
- dput(sb->s_root);
- sb->s_root = NULL;
+ iput(root);
printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
goto failed_mount3;
}
+
+ sb->s_root = d_alloc_root(root);
+ if (!sb->s_root) {
+ iput(root);
+ printk(KERN_ERR "EXT2-fs: get root inode failed\n");
+ ret = -ENOMEM;
+ goto failed_mount3;
+ }
if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
ext2_warning(sb, __FUNCTION__,
"mounting ext3 filesystem as ext2");
@@ -957,7 +961,7 @@ failed_mount:
failed_sbi:
sb->s_fs_info = NULL;
kfree(sbi);
- return -EINVAL;
+ return ret;
}

static void ext2_commit_super (struct super_block * sb,

2007-10-10 21:48:51

by David Howells

[permalink] [raw]
Subject: [PATCH 13/31] IGET: Stop EXT3 from using iget() and read_inode() [try #3]

Stop the EXT3 filesystem from using iget() and read_inode(). Replace
ext3_read_inode() with ext3_iget(), and call that instead of iget().
ext3_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

ext3_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
Acked-by: "Theodore Ts'o" <[email protected]>
Acked-by: Jan Kara <[email protected]>
---

fs/ext3/ialloc.c | 58 ++++++++++++++++++++++++++++-------------------
fs/ext3/inode.c | 25 +++++++++++++++-----
fs/ext3/namei.c | 29 +++++++-----------------
fs/ext3/resize.c | 7 ++----
fs/ext3/super.c | 40 ++++++++++++++++++--------------
include/linux/ext3_fs.h | 2 +-
6 files changed, 89 insertions(+), 72 deletions(-)

diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index e45dbd6..5724adb 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -645,14 +645,15 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
unsigned long max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count);
unsigned long block_group;
int bit;
- struct buffer_head *bitmap_bh = NULL;
+ struct buffer_head *bitmap_bh;
struct inode *inode = NULL;
+ long err = -EIO;

/* Error cases - e2fsck has already cleaned up for us */
if (ino > max_ino) {
ext3_warning(sb, __FUNCTION__,
"bad orphan ino %lu! e2fsck was run?", ino);
- goto out;
+ goto error;
}

block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
@@ -661,38 +662,49 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
if (!bitmap_bh) {
ext3_warning(sb, __FUNCTION__,
"inode bitmap error for orphan %lu", ino);
- goto out;
+ goto error;
}

/* Having the inode bit set should be a 100% indicator that this
* is a valid orphan (no e2fsck run on fs). Orphans also include
* inodes that were being truncated, so we can't check i_nlink==0.
*/
- if (!ext3_test_bit(bit, bitmap_bh->b_data) ||
- !(inode = iget(sb, ino)) || is_bad_inode(inode) ||
- NEXT_ORPHAN(inode) > max_ino) {
- ext3_warning(sb, __FUNCTION__,
- "bad orphan inode %lu! e2fsck was run?", ino);
- printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n",
- bit, (unsigned long long)bitmap_bh->b_blocknr,
- ext3_test_bit(bit, bitmap_bh->b_data));
- printk(KERN_NOTICE "inode=%p\n", inode);
- if (inode) {
- printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
- is_bad_inode(inode));
- printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
- NEXT_ORPHAN(inode));
- printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
- }
+ if (!ext3_test_bit(bit, bitmap_bh->b_data))
+ goto bad_orphan;
+
+ inode = ext3_iget(sb, ino);
+ if (IS_ERR(inode))
+ goto iget_failed;
+
+ if (NEXT_ORPHAN(inode) > max_ino)
+ goto bad_orphan;
+ brelse(bitmap_bh);
+ return inode;
+
+iget_failed:
+ err = PTR_ERR(inode);
+ inode = NULL;
+bad_orphan:
+ ext3_warning(sb, __FUNCTION__,
+ "bad orphan inode %lu! e2fsck was run?", ino);
+ printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n",
+ bit, (unsigned long long)bitmap_bh->b_blocknr,
+ ext3_test_bit(bit, bitmap_bh->b_data));
+ printk(KERN_NOTICE "inode=%p\n", inode);
+ if (inode) {
+ printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
+ is_bad_inode(inode));
+ printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
+ NEXT_ORPHAN(inode));
+ printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
/* Avoid freeing blocks if we got a bad deleted inode */
- if (inode && inode->i_nlink == 0)
+ if (inode->i_nlink == 0)
inode->i_blocks = 0;
iput(inode);
- inode = NULL;
}
-out:
brelse(bitmap_bh);
- return inode;
+error:
+ return ERR_PTR(err);
}

unsigned long ext3_count_free_inodes (struct super_block * sb)
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index de4e316..6c74622 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -2591,21 +2591,31 @@ void ext3_get_inode_flags(struct ext3_inode_info *ei)
ei->i_flags |= EXT3_DIRSYNC_FL;
}

-void ext3_read_inode(struct inode * inode)
+struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
{
struct ext3_iloc iloc;
struct ext3_inode *raw_inode;
- struct ext3_inode_info *ei = EXT3_I(inode);
+ struct ext3_inode_info *ei;
struct buffer_head *bh;
+ struct inode *inode;
+ long ret;
int block;

+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ ei = EXT3_I(inode);
#ifdef CONFIG_EXT3_FS_POSIX_ACL
ei->i_acl = EXT3_ACL_NOT_CACHED;
ei->i_default_acl = EXT3_ACL_NOT_CACHED;
#endif
ei->i_block_alloc_info = NULL;

- if (__ext3_get_inode_loc(inode, &iloc, 0))
+ ret = __ext3_get_inode_loc(inode, &iloc, 0);
+ if (ret < 0)
goto bad_inode;
bh = iloc.bh;
raw_inode = ext3_raw_inode(&iloc);
@@ -2636,6 +2646,7 @@ void ext3_read_inode(struct inode * inode)
!(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ORPHAN_FS)) {
/* this inode is deleted */
brelse (bh);
+ ret = -ESTALE;
goto bad_inode;
}
/* The only unlinked inodes we let through here have
@@ -2679,6 +2690,7 @@ void ext3_read_inode(struct inode * inode)
if (EXT3_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
EXT3_INODE_SIZE(inode->i_sb)) {
brelse (bh);
+ ret = -EIO;
goto bad_inode;
}
if (ei->i_extra_isize == 0) {
@@ -2720,11 +2732,12 @@ void ext3_read_inode(struct inode * inode)
}
brelse (iloc.bh);
ext3_set_inode_flags(inode);
- return;
+ unlock_new_inode(inode);
+ return inode;

bad_inode:
- make_bad_inode(inode);
- return;
+ iget_failed(inode);
+ return ERR_PTR(ret);
}

/*
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index c1fa190..6919a18 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1046,17 +1046,11 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
if (!ext3_valid_inum(dir->i_sb, ino)) {
ext3_error(dir->i_sb, "ext3_lookup",
"bad inode number: %lu", ino);
- inode = NULL;
- } else
- inode = iget(dir->i_sb, ino);
-
- if (!inode)
- return ERR_PTR(-EACCES);
-
- if (is_bad_inode(inode)) {
- iput(inode);
- return ERR_PTR(-ENOENT);
+ return ERR_PTR(-EIO);
}
+ inode = ext3_iget(dir->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
}
return d_splice_alias(inode, dentry);
}
@@ -1085,18 +1079,13 @@ struct dentry *ext3_get_parent(struct dentry *child)
if (!ext3_valid_inum(child->d_inode->i_sb, ino)) {
ext3_error(child->d_inode->i_sb, "ext3_get_parent",
"bad inode number: %lu", ino);
- inode = NULL;
- } else
- inode = iget(child->d_inode->i_sb, ino);
-
- if (!inode)
- return ERR_PTR(-EACCES);
-
- if (is_bad_inode(inode)) {
- iput(inode);
- return ERR_PTR(-ENOENT);
+ return ERR_PTR(-EIO);
}

+ inode = ext3_iget(child->d_inode->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
+
parent = d_alloc_anon(inode);
if (!parent) {
iput(inode);
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index 2c97e09..60b6530 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -748,12 +748,11 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
"No reserved GDT blocks, can't resize");
return -EPERM;
}
- inode = iget(sb, EXT3_RESIZE_INO);
- if (!inode || is_bad_inode(inode)) {
+ inode = ext3_iget(sb, EXT3_RESIZE_INO);
+ if (IS_ERR(inode)) {
ext3_warning(sb, __FUNCTION__,
"Error opening resize inode");
- iput(inode);
- return -ENOENT;
+ return PTR_ERR(inode);
}
}

diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 9537316..add683b 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -583,11 +583,10 @@ static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp)
* Currently we don't know the generation for parent directory, so
* a generation of 0 means "accept any"
*/
- inode = iget(sb, ino);
- if (inode == NULL)
- return ERR_PTR(-ENOMEM);
- if (is_bad_inode(inode) ||
- (generation && inode->i_generation != generation)) {
+ inode = ext3_iget(sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
+ if (generation && inode->i_generation != generation) {
iput(inode);
return ERR_PTR(-ESTALE);
}
@@ -649,7 +648,6 @@ static struct quotactl_ops ext3_qctl_operations = {
static const struct super_operations ext3_sops = {
.alloc_inode = ext3_alloc_inode,
.destroy_inode = ext3_destroy_inode,
- .read_inode = ext3_read_inode,
.write_inode = ext3_write_inode,
.dirty_inode = ext3_dirty_inode,
.delete_inode = ext3_delete_inode,
@@ -1309,8 +1307,8 @@ static void ext3_orphan_cleanup (struct super_block * sb,
while (es->s_last_orphan) {
struct inode *inode;

- if (!(inode =
- ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) {
+ inode = ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan));
+ if (IS_ERR(inode)) {
es->s_last_orphan = 0;
break;
}
@@ -1415,6 +1413,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
int db_count;
int i;
int needs_recovery;
+ int ret = -EINVAL;
__le32 features;

sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
@@ -1770,19 +1769,24 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
* so we can safely mount the rest of the filesystem now.
*/

- root = iget(sb, EXT3_ROOT_INO);
- sb->s_root = d_alloc_root(root);
- if (!sb->s_root) {
+ root = ext3_iget(sb, EXT3_ROOT_INO);
+ if (IS_ERR(root)) {
printk(KERN_ERR "EXT3-fs: get root inode failed\n");
- iput(root);
+ ret = PTR_ERR(root);
goto failed_mount4;
}
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
- dput(sb->s_root);
- sb->s_root = NULL;
+ iput(root);
printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n");
goto failed_mount4;
}
+ sb->s_root = d_alloc_root(root);
+ if (!sb->s_root) {
+ printk(KERN_ERR "EXT3-fs: get root dentry failed\n");
+ iput(root);
+ ret = -ENOMEM;
+ goto failed_mount4;
+ }

ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
/*
@@ -1834,7 +1838,7 @@ out_fail:
sb->s_fs_info = NULL;
kfree(sbi);
lock_kernel();
- return -EINVAL;
+ return ret;
}

/*
@@ -1870,8 +1874,8 @@ static journal_t *ext3_get_journal(struct super_block *sb,
* things happen if we iget() an unused inode, as the subsequent
* iput() will try to delete it. */

- journal_inode = iget(sb, journal_inum);
- if (!journal_inode) {
+ journal_inode = ext3_iget(sb, journal_inum);
+ if (IS_ERR(journal_inode)) {
printk(KERN_ERR "EXT3-fs: no journal found.\n");
return NULL;
}
@@ -1884,7 +1888,7 @@ static journal_t *ext3_get_journal(struct super_block *sb,

jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
journal_inode, journal_inode->i_size);
- if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) {
+ if (!S_ISREG(journal_inode->i_mode)) {
printk(KERN_ERR "EXT3-fs: invalid journal inode.\n");
iput(journal_inode);
return NULL;
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index ece49a8..a5ccfea 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -813,7 +813,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
int create, int extend_disksize);

-extern void ext3_read_inode (struct inode *);
+extern struct inode *ext3_iget (struct super_block *, unsigned long);
extern int ext3_write_inode (struct inode *, int);
extern int ext3_setattr (struct dentry *, struct iattr *);
extern void ext3_delete_inode (struct inode *);

2007-10-10 21:49:16

by David Howells

[permalink] [raw]
Subject: [PATCH 14/31] IGET: Stop EXT4 from using iget() and read_inode() [try #3]

Stop the EXT4 filesystem from using iget() and read_inode(). Replace
ext4_read_inode() with ext4_iget(), and call that instead of iget().
ext4_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

ext4_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
Acked-by: "Theodore Ts'o" <[email protected]>
Acked-by: Jan Kara <[email protected]>
---

fs/ext4/ialloc.c | 58 ++++++++++++++++++++++++++++-------------------
fs/ext4/inode.c | 25 +++++++++++++++-----
fs/ext4/namei.c | 29 +++++++-----------------
fs/ext4/resize.c | 7 ++----
fs/ext4/super.c | 36 ++++++++++++++++-------------
include/linux/ext4_fs.h | 2 +-
6 files changed, 87 insertions(+), 70 deletions(-)

diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 427f830..4fba007 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -659,14 +659,15 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
unsigned long max_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count);
unsigned long block_group;
int bit;
- struct buffer_head *bitmap_bh = NULL;
+ struct buffer_head *bitmap_bh;
struct inode *inode = NULL;
+ long err = -EIO;

/* Error cases - e2fsck has already cleaned up for us */
if (ino > max_ino) {
ext4_warning(sb, __FUNCTION__,
"bad orphan ino %lu! e2fsck was run?", ino);
- goto out;
+ goto error;
}

block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
@@ -675,38 +676,49 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
if (!bitmap_bh) {
ext4_warning(sb, __FUNCTION__,
"inode bitmap error for orphan %lu", ino);
- goto out;
+ goto error;
}

/* Having the inode bit set should be a 100% indicator that this
* is a valid orphan (no e2fsck run on fs). Orphans also include
* inodes that were being truncated, so we can't check i_nlink==0.
*/
- if (!ext4_test_bit(bit, bitmap_bh->b_data) ||
- !(inode = iget(sb, ino)) || is_bad_inode(inode) ||
- NEXT_ORPHAN(inode) > max_ino) {
- ext4_warning(sb, __FUNCTION__,
- "bad orphan inode %lu! e2fsck was run?", ino);
- printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n",
- bit, (unsigned long long)bitmap_bh->b_blocknr,
- ext4_test_bit(bit, bitmap_bh->b_data));
- printk(KERN_NOTICE "inode=%p\n", inode);
- if (inode) {
- printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
- is_bad_inode(inode));
- printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
- NEXT_ORPHAN(inode));
- printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
- }
+ if (!ext4_test_bit(bit, bitmap_bh->b_data))
+ goto bad_orphan;
+
+ inode = ext4_iget(sb, ino);
+ if (IS_ERR(inode))
+ goto iget_failed;
+
+ if (NEXT_ORPHAN(inode) > max_ino)
+ goto bad_orphan;
+ brelse(bitmap_bh);
+ return inode;
+
+iget_failed:
+ err = PTR_ERR(inode);
+ inode = NULL;
+bad_orphan:
+ ext4_warning(sb, __FUNCTION__,
+ "bad orphan inode %lu! e2fsck was run?", ino);
+ printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n",
+ bit, (unsigned long long)bitmap_bh->b_blocknr,
+ ext4_test_bit(bit, bitmap_bh->b_data));
+ printk(KERN_NOTICE "inode=%p\n", inode);
+ if (inode) {
+ printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
+ is_bad_inode(inode));
+ printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
+ NEXT_ORPHAN(inode));
+ printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
/* Avoid freeing blocks if we got a bad deleted inode */
- if (inode && inode->i_nlink == 0)
+ if (inode->i_nlink == 0)
inode->i_blocks = 0;
iput(inode);
- inode = NULL;
}
-out:
brelse(bitmap_bh);
- return inode;
+error:
+ return ERR_PTR(err);
}

unsigned long ext4_count_free_inodes (struct super_block * sb)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index a4848e0..c4fb1eb 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2595,21 +2595,31 @@ void ext4_get_inode_flags(struct ext4_inode_info *ei)
ei->i_flags |= EXT4_DIRSYNC_FL;
}

-void ext4_read_inode(struct inode * inode)
+struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
{
struct ext4_iloc iloc;
struct ext4_inode *raw_inode;
- struct ext4_inode_info *ei = EXT4_I(inode);
+ struct ext4_inode_info *ei;
struct buffer_head *bh;
+ struct inode *inode;
+ long ret;
int block;

+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ ei = EXT4_I(inode);
#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
ei->i_acl = EXT4_ACL_NOT_CACHED;
ei->i_default_acl = EXT4_ACL_NOT_CACHED;
#endif
ei->i_block_alloc_info = NULL;

- if (__ext4_get_inode_loc(inode, &iloc, 0))
+ ret = __ext4_get_inode_loc(inode, &iloc, 0);
+ if (ret < 0)
goto bad_inode;
bh = iloc.bh;
raw_inode = ext4_raw_inode(&iloc);
@@ -2636,6 +2646,7 @@ void ext4_read_inode(struct inode * inode)
!(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) {
/* this inode is deleted */
brelse (bh);
+ ret = -ESTALE;
goto bad_inode;
}
/* The only unlinked inodes we let through here have
@@ -2683,6 +2694,7 @@ void ext4_read_inode(struct inode * inode)
if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
EXT4_INODE_SIZE(inode->i_sb)) {
brelse (bh);
+ ret = -EIO;
goto bad_inode;
}
if (ei->i_extra_isize == 0) {
@@ -2729,11 +2741,12 @@ void ext4_read_inode(struct inode * inode)
}
brelse (iloc.bh);
ext4_set_inode_flags(inode);
- return;
+ unlock_new_inode(inode);
+ return inode;

bad_inode:
- make_bad_inode(inode);
- return;
+ iget_failed(inode);
+ return ERR_PTR(ret);
}

/*
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 5fdb862..301f41f 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1044,17 +1044,11 @@ static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, str
if (!ext4_valid_inum(dir->i_sb, ino)) {
ext4_error(dir->i_sb, "ext4_lookup",
"bad inode number: %lu", ino);
- inode = NULL;
- } else
- inode = iget(dir->i_sb, ino);
-
- if (!inode)
- return ERR_PTR(-EACCES);
-
- if (is_bad_inode(inode)) {
- iput(inode);
- return ERR_PTR(-ENOENT);
+ return ERR_PTR(-EIO);
}
+ inode = ext4_iget(dir->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
}
return d_splice_alias(inode, dentry);
}
@@ -1083,18 +1077,13 @@ struct dentry *ext4_get_parent(struct dentry *child)
if (!ext4_valid_inum(child->d_inode->i_sb, ino)) {
ext4_error(child->d_inode->i_sb, "ext4_get_parent",
"bad inode number: %lu", ino);
- inode = NULL;
- } else
- inode = iget(child->d_inode->i_sb, ino);
-
- if (!inode)
- return ERR_PTR(-EACCES);
-
- if (is_bad_inode(inode)) {
- iput(inode);
- return ERR_PTR(-ENOENT);
+ return ERR_PTR(-EIO);
}

+ inode = ext4_iget(child->d_inode->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
+
parent = d_alloc_anon(inode);
if (!parent) {
iput(inode);
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index aa11d7d..345f901 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -757,12 +757,11 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
"No reserved GDT blocks, can't resize");
return -EPERM;
}
- inode = iget(sb, EXT4_RESIZE_INO);
- if (!inode || is_bad_inode(inode)) {
+ inode = ext4_iget(sb, EXT4_RESIZE_INO);
+ if (IS_ERR(inode)) {
ext4_warning(sb, __FUNCTION__,
"Error opening resize inode");
- iput(inode);
- return -ENOENT;
+ return PTR_ERR(inode);
}
}

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 3c1397f..05434a1 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -634,11 +634,10 @@ static struct dentry *ext4_get_dentry(struct super_block *sb, void *vobjp)
* Currently we don't know the generation for parent directory, so
* a generation of 0 means "accept any"
*/
- inode = iget(sb, ino);
- if (inode == NULL)
- return ERR_PTR(-ENOMEM);
- if (is_bad_inode(inode) ||
- (generation && inode->i_generation != generation)) {
+ inode = ext4_iget(sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
+ if (generation && inode->i_generation != generation) {
iput(inode);
return ERR_PTR(-ESTALE);
}
@@ -700,7 +699,6 @@ static struct quotactl_ops ext4_qctl_operations = {
static const struct super_operations ext4_sops = {
.alloc_inode = ext4_alloc_inode,
.destroy_inode = ext4_destroy_inode,
- .read_inode = ext4_read_inode,
.write_inode = ext4_write_inode,
.dirty_inode = ext4_dirty_inode,
.delete_inode = ext4_delete_inode,
@@ -1472,6 +1470,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
unsigned long journal_devnum = 0;
unsigned long def_mount_opts;
struct inode *root;
+ int ret = -EINVAL;
int blocksize;
int hblock;
int db_count;
@@ -1862,19 +1861,24 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
* so we can safely mount the rest of the filesystem now.
*/

- root = iget(sb, EXT4_ROOT_INO);
- sb->s_root = d_alloc_root(root);
- if (!sb->s_root) {
+ root = ext4_iget(sb, EXT4_ROOT_INO);
+ if (IS_ERR(root)) {
printk(KERN_ERR "EXT4-fs: get root inode failed\n");
- iput(root);
+ ret = PTR_ERR(root);
goto failed_mount4;
}
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
- dput(sb->s_root);
- sb->s_root = NULL;
+ iput(root);
printk(KERN_ERR "EXT4-fs: corrupt root inode, run e2fsck\n");
goto failed_mount4;
}
+ sb->s_root = d_alloc_root(root);
+ if (!sb->s_root) {
+ printk(KERN_ERR "EXT4-fs: get root dentry failed\n");
+ iput(root);
+ ret = -ENOMEM;
+ goto failed_mount4;
+ }

ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);

@@ -1954,7 +1958,7 @@ out_fail:
sb->s_fs_info = NULL;
kfree(sbi);
lock_kernel();
- return -EINVAL;
+ return ret;
}

/*
@@ -1990,8 +1994,8 @@ static journal_t *ext4_get_journal(struct super_block *sb,
* things happen if we iget() an unused inode, as the subsequent
* iput() will try to delete it. */

- journal_inode = iget(sb, journal_inum);
- if (!journal_inode) {
+ journal_inode = ext4_iget(sb, journal_inum);
+ if (IS_ERR(journal_inode)) {
printk(KERN_ERR "EXT4-fs: no journal found.\n");
return NULL;
}
@@ -2004,7 +2008,7 @@ static journal_t *ext4_get_journal(struct super_block *sb,

jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
journal_inode, journal_inode->i_size);
- if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) {
+ if (!S_ISREG(journal_inode->i_mode)) {
printk(KERN_ERR "EXT4-fs: invalid journal inode.\n");
iput(journal_inode);
return NULL;
diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
index cdee7aa..12354d5 100644
--- a/include/linux/ext4_fs.h
+++ b/include/linux/ext4_fs.h
@@ -944,7 +944,7 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
int create, int extend_disksize);

-extern void ext4_read_inode (struct inode *);
+extern struct inode *ext4_iget(struct super_block *, unsigned long);
extern int ext4_write_inode (struct inode *, int);
extern int ext4_setattr (struct dentry *, struct iattr *);
extern void ext4_delete_inode (struct inode *);

2007-10-10 21:49:35

by David Howells

[permalink] [raw]
Subject: [PATCH 15/31] IGET: Stop FAT from using iget() and read_inode() [try #3]

Stop the FAT filesystem from using iget() and read_inode(). Replace
the call to iget() with a call to ilookup().

Signed-off-by: David Howells <[email protected]>
---

fs/fat/inode.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 960ed3d..9ae2e9f 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -629,8 +629,6 @@ static const struct super_operations fat_sops = {
.clear_inode = fat_clear_inode,
.remount_fs = fat_remount,

- .read_inode = make_bad_inode,
-
.show_options = fat_show_options,
};

@@ -667,8 +665,8 @@ static struct dentry *fat_get_dentry(struct super_block *sb, void *inump)
struct dentry *result;
__u32 *fh = inump;

- inode = iget(sb, fh[0]);
- if (!inode || is_bad_inode(inode) || inode->i_generation != fh[1]) {
+ inode = ilookup(sb, fh[0]);
+ if (!inode || inode->i_generation != fh[1]) {
if (inode)
iput(inode);
inode = NULL;

2007-10-10 21:49:50

by David Howells

[permalink] [raw]
Subject: [PATCH 16/31] IGET: Stop FreeVXFS from using iget() and read_inode() [try #3]

Stop the FreeVXFS filesystem from using iget() and read_inode(). Replace
vxfs_read_inode() with vxfs_iget(), and call that instead of iget().
vxfs_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

vxfs_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
---

fs/freevxfs/vxfs_extern.h | 2 +-
fs/freevxfs/vxfs_inode.c | 45 +++++++++++++++++++++++++++++----------------
fs/freevxfs/vxfs_lookup.c | 6 +++---
fs/freevxfs/vxfs_super.c | 10 +++++++---
4 files changed, 40 insertions(+), 23 deletions(-)

diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h
index 91ccee8..f307694 100644
--- a/fs/freevxfs/vxfs_extern.h
+++ b/fs/freevxfs/vxfs_extern.h
@@ -58,7 +58,7 @@ extern struct inode * vxfs_get_fake_inode(struct super_block *,
extern void vxfs_put_fake_inode(struct inode *);
extern struct vxfs_inode_info * vxfs_blkiget(struct super_block *, u_long, ino_t);
extern struct vxfs_inode_info * vxfs_stiget(struct super_block *, ino_t);
-extern void vxfs_read_inode(struct inode *);
+extern struct inode * vxfs_iget(struct super_block *, unsigned long);
extern void vxfs_clear_inode(struct inode *);

/* vxfs_lookup.c */
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index d1f7c5b..95a0af9 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -129,7 +129,7 @@ fail:
* Description:
* Search the for inode number @ino in the filesystem
* described by @sbp. Use the specified inode table (@ilistp).
- * Returns the matching VxFS inode on success, else a NULL pointer.
+ * Returns the matching VxFS inode on success, else an error code.
*/
static struct vxfs_inode_info *
__vxfs_iget(ino_t ino, struct inode *ilistp)
@@ -157,12 +157,12 @@ __vxfs_iget(ino_t ino, struct inode *ilistp)
}

printk(KERN_WARNING "vxfs: error on page %p\n", pp);
- return NULL;
+ return ERR_CAST(pp);

fail:
printk(KERN_WARNING "vxfs: unable to read inode %ld\n", (unsigned long)ino);
vxfs_put_page(pp);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}

/**
@@ -178,7 +178,10 @@ fail:
struct vxfs_inode_info *
vxfs_stiget(struct super_block *sbp, ino_t ino)
{
- return __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
+ struct vxfs_inode_info *vip;
+
+ vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
+ return IS_ERR(vip) ? NULL : vip;
}

/**
@@ -282,23 +285,32 @@ vxfs_put_fake_inode(struct inode *ip)
}

/**
- * vxfs_read_inode - fill in inode information
- * @ip: inode pointer to fill
+ * vxfs_iget - get an inode
+ * @sbp: the superblock to get the inode for
+ * @ino: the number of the inode to get
*
* Description:
- * vxfs_read_inode reads the disk inode for @ip and fills
- * in all relevant fields in @ip.
+ * vxfs_read_inode creates an inode, reads the disk inode for @ino and fills
+ * in all relevant fields in the new inode.
*/
-void
-vxfs_read_inode(struct inode *ip)
+struct inode *
+vxfs_iget(struct super_block *sbp, ino_t ino)
{
- struct super_block *sbp = ip->i_sb;
struct vxfs_inode_info *vip;
const struct address_space_operations *aops;
- ino_t ino = ip->i_ino;
-
- if (!(vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist)))
- return;
+ struct inode *ip;
+
+ ip = iget_locked(sbp, ino);
+ if (!ip)
+ return ERR_PTR(-ENOMEM);
+ if (!(ip->i_state & I_NEW))
+ return ip;
+
+ vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist);
+ if (IS_ERR(vip)) {
+ iget_failed(ip);
+ return ERR_CAST(vip);
+ }

vxfs_iinit(ip, vip);

@@ -323,7 +335,8 @@ vxfs_read_inode(struct inode *ip)
} else
init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev));

- return;
+ unlock_new_inode(ip);
+ return ip;
}

/**
diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
index bf86e54..aee049c 100644
--- a/fs/freevxfs/vxfs_lookup.c
+++ b/fs/freevxfs/vxfs_lookup.c
@@ -213,10 +213,10 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd)
lock_kernel();
ino = vxfs_inode_by_name(dip, dp);
if (ino) {
- ip = iget(dip->i_sb, ino);
- if (!ip) {
+ ip = vxfs_iget(dip->i_sb, ino);
+ if (IS_ERR(ip)) {
unlock_kernel();
- return ERR_PTR(-EACCES);
+ return ERR_CAST(ip);
}
}
unlock_kernel();
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index 4f95572..1dacda8 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -60,7 +60,6 @@ static int vxfs_statfs(struct dentry *, struct kstatfs *);
static int vxfs_remount(struct super_block *, int *, char *);

static const struct super_operations vxfs_super_ops = {
- .read_inode = vxfs_read_inode,
.clear_inode = vxfs_clear_inode,
.put_super = vxfs_put_super,
.statfs = vxfs_statfs,
@@ -153,6 +152,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
struct buffer_head *bp = NULL;
u_long bsize;
struct inode *root;
+ int ret = -EINVAL;

sbp->s_flags |= MS_RDONLY;

@@ -219,7 +219,11 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
}

sbp->s_op = &vxfs_super_ops;
- root = iget(sbp, VXFS_ROOT_INO);
+ root = vxfs_iget(sbp, VXFS_ROOT_INO);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
+ goto out;
+ }
sbp->s_root = d_alloc_root(root);
if (!sbp->s_root) {
iput(root);
@@ -236,7 +240,7 @@ out_free_ilist:
out:
brelse(bp);
kfree(infp);
- return -EINVAL;
+ return ret;
}

/*

2007-10-10 21:50:09

by David Howells

[permalink] [raw]
Subject: [PATCH 17/31] IGET: Stop FUSE from using iget() and read_inode() [try #3]

Stop the FUSE filesystem from using read_inode(), which it doesn't use anyway.

Signed-off-by: David Howells <[email protected]>
---

fs/fuse/inode.c | 6 ------
1 files changed, 0 insertions(+), 6 deletions(-)

diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 5448f62..2986654 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -73,11 +73,6 @@ static void fuse_destroy_inode(struct inode *inode)
kmem_cache_free(fuse_inode_cachep, inode);
}

-static void fuse_read_inode(struct inode *inode)
-{
- /* No op */
-}
-
void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
unsigned long nodeid, u64 nlookup)
{
@@ -452,7 +447,6 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
static const struct super_operations fuse_super_operations = {
.alloc_inode = fuse_alloc_inode,
.destroy_inode = fuse_destroy_inode,
- .read_inode = fuse_read_inode,
.clear_inode = fuse_clear_inode,
.drop_inode = generic_delete_inode,
.remount_fs = fuse_remount_fs,

2007-10-10 21:50:38

by David Howells

[permalink] [raw]
Subject: [PATCH 18/31] IGET: Stop HFSPLUS from using iget() and read_inode() [try #3]

Stop the HFSPLUS filesystem from using iget() and read_inode(). Replace
hfsplus_read_inode() with hfsplus_iget(), and call that instead of iget().
hfsplus_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

hfsplus_fill_super() returns any error incurred when getting the root inode.

Signed-off-by: David Howells <[email protected]>
---

fs/hfsplus/btree.c | 6 ++++--
fs/hfsplus/dir.c | 6 +++---
fs/hfsplus/hfsplus_fs.h | 3 +++
fs/hfsplus/super.c | 44 ++++++++++++++++++++++++++++++++------------
4 files changed, 42 insertions(+), 17 deletions(-)

diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index 050d29c..bb54336 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -22,6 +22,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
struct hfs_btree *tree;
struct hfs_btree_header_rec *head;
struct address_space *mapping;
+ struct inode *inode;
struct page *page;
unsigned int size;

@@ -33,9 +34,10 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
spin_lock_init(&tree->hash_lock);
tree->sb = sb;
tree->cnid = id;
- tree->inode = iget(sb, id);
- if (!tree->inode)
+ inode = hfsplus_iget(sb, id);
+ if (IS_ERR(inode))
goto free_tree;
+ tree->inode = inode;

mapping = tree->inode->i_mapping;
page = read_mapping_page(mapping, 0, NULL);
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 1955ee6..2968364 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -97,9 +97,9 @@ again:
goto fail;
}
hfs_find_exit(&fd);
- inode = iget(dir->i_sb, cnid);
- if (!inode)
- return ERR_PTR(-EACCES);
+ inode = hfsplus_iget(dir->i_sb, cnid);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
if (S_ISREG(inode->i_mode))
HFSPLUS_I(inode).dev = linkid;
out:
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index d9f5eda..d72d0a8 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -345,6 +345,9 @@ int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
void hfsplus_fill_defaults(struct hfsplus_sb_info *);
int hfsplus_show_options(struct seq_file *, struct vfsmount *);

+/* super.c */
+struct inode *hfsplus_iget(struct super_block *, unsigned long);
+
/* tables.c */
extern u16 hfsplus_case_fold_table[];
extern u16 hfsplus_decompose_table[];
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 7b0f2e5..0b45d97 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -20,11 +20,18 @@ static void hfsplus_destroy_inode(struct inode *inode);

#include "hfsplus_fs.h"

-static void hfsplus_read_inode(struct inode *inode)
+struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
{
struct hfs_find_data fd;
struct hfsplus_vh *vhdr;
- int err;
+ struct inode *inode;
+ long err = -EIO;
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;

INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
init_MUTEX(&HFSPLUS_I(inode).extents_lock);
@@ -41,7 +48,7 @@ static void hfsplus_read_inode(struct inode *inode)
hfs_find_exit(&fd);
if (err)
goto bad_inode;
- return;
+ goto done;
}
vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr;
switch(inode->i_ino) {
@@ -70,10 +77,14 @@ static void hfsplus_read_inode(struct inode *inode)
goto bad_inode;
}

- return;
+done:
+ unlock_new_inode(inode);
+ return inode;

bad_inode:
make_bad_inode(inode);
+ iput(inode);
+ return ERR_PTR(err);
}

static int hfsplus_write_inode(struct inode *inode, int unused)
@@ -262,7 +273,6 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
static const struct super_operations hfsplus_sops = {
.alloc_inode = hfsplus_alloc_inode,
.destroy_inode = hfsplus_destroy_inode,
- .read_inode = hfsplus_read_inode,
.write_inode = hfsplus_write_inode,
.clear_inode = hfsplus_clear_inode,
.put_super = hfsplus_put_super,
@@ -278,7 +288,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
struct hfsplus_sb_info *sbi;
hfsplus_cat_entry entry;
struct hfs_find_data fd;
- struct inode *root;
+ struct inode *root, *inode;
struct qstr str;
struct nls_table *nls = NULL;
int err = -EINVAL;
@@ -366,18 +376,25 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
goto cleanup;
}

- HFSPLUS_SB(sb).alloc_file = iget(sb, HFSPLUS_ALLOC_CNID);
- if (!HFSPLUS_SB(sb).alloc_file) {
+ inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
+ if (IS_ERR(inode)) {
printk(KERN_ERR "hfs: failed to load allocation file\n");
+ err = PTR_ERR(inode);
goto cleanup;
}
+ HFSPLUS_SB(sb).alloc_file = inode;

/* Load the root directory */
- root = iget(sb, HFSPLUS_ROOT_CNID);
+ root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
+ if (IS_ERR(root)) {
+ printk(KERN_ERR "hfs: failed to load root directory\n");
+ err = PTR_ERR(root);
+ goto cleanup;
+ }
sb->s_root = d_alloc_root(root);
if (!sb->s_root) {
- printk(KERN_ERR "hfs: failed to load root directory\n");
iput(root);
+ err = -ENOMEM;
goto cleanup;
}
sb->s_root->d_op = &hfsplus_dentry_operations;
@@ -390,9 +407,12 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
hfs_find_exit(&fd);
if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
goto cleanup;
- HFSPLUS_SB(sb).hidden_dir = iget(sb, be32_to_cpu(entry.folder.id));
- if (!HFSPLUS_SB(sb).hidden_dir)
+ inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
goto cleanup;
+ }
+ HFSPLUS_SB(sb).hidden_dir = inode;
} else
hfs_find_exit(&fd);


2007-10-10 21:50:54

by David Howells

[permalink] [raw]
Subject: [PATCH 19/31] IGET: Stop ISOFS from using read_inode() [try #3]

Stop the ISOFS filesystem from using read_inode(). Make isofs_read_inode()
return an error code, and make isofs_iget() pass it on.

Signed-off-by: David Howells <[email protected]>
---

fs/isofs/inode.c | 25 +++++++++++++++++--------
1 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 043b470..28d990b 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -54,7 +54,7 @@ static void isofs_put_super(struct super_block *sb)
return;
}

-static void isofs_read_inode(struct inode *);
+static int isofs_read_inode(struct inode *);
static int isofs_statfs (struct dentry *, struct kstatfs *);

static struct kmem_cache *isofs_inode_cachep;
@@ -107,7 +107,6 @@ static int isofs_remount(struct super_block *sb, int *flags, char *data)
static const struct super_operations isofs_sops = {
.alloc_inode = isofs_alloc_inode,
.destroy_inode = isofs_destroy_inode,
- .read_inode = isofs_read_inode,
.put_super = isofs_put_super,
.statfs = isofs_statfs,
.remount_fs = isofs_remount,
@@ -1186,7 +1185,7 @@ out_toomany:
goto out;
}

-static void isofs_read_inode(struct inode *inode)
+static int isofs_read_inode(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
struct isofs_sb_info *sbi = ISOFS_SB(sb);
@@ -1199,6 +1198,7 @@ static void isofs_read_inode(struct inode *inode)
unsigned int de_len;
unsigned long offset;
struct iso_inode_info *ei = ISOFS_I(inode);
+ int ret = -EIO;

block = ei->i_iget5_block;
bh = sb_bread(inode->i_sb, block);
@@ -1216,6 +1216,7 @@ static void isofs_read_inode(struct inode *inode)
tmpde = kmalloc(de_len, GFP_KERNEL);
if (tmpde == NULL) {
printk(KERN_INFO "%s: out of memory\n", __func__);
+ ret = -ENOMEM;
goto fail;
}
memcpy(tmpde, bh->b_data + offset, frag1);
@@ -1259,8 +1260,10 @@ static void isofs_read_inode(struct inode *inode)

ei->i_section_size = isonum_733(de->size);
if (de->flags[-high_sierra] & 0x80) {
- if(isofs_read_level3_size(inode))
+ ret = isofs_read_level3_size(inode);
+ if (ret < 0)
goto fail;
+ ret = -EIO;
} else {
ei->i_next_section_block = 0;
ei->i_next_section_offset = 0;
@@ -1346,16 +1349,16 @@ static void isofs_read_inode(struct inode *inode)
/* XXX - parse_rock_ridge_inode() had already set i_rdev. */
init_special_inode(inode, inode->i_mode, inode->i_rdev);

+ ret = 0;
out:
kfree(tmpde);
if (bh)
brelse(bh);
- return;
+ return ret;

out_badread:
printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
fail:
- make_bad_inode(inode);
goto out;
}

@@ -1394,6 +1397,7 @@ struct inode *isofs_iget(struct super_block *sb,
unsigned long hashval;
struct inode *inode;
struct isofs_iget5_callback_data data;
+ long ret;

if (offset >= 1ul << sb->s_blocksize_bits)
return NULL;
@@ -1407,8 +1411,13 @@ struct inode *isofs_iget(struct super_block *sb,
&isofs_iget5_set, &data);

if (inode && (inode->i_state & I_NEW)) {
- sb->s_op->read_inode(inode);
- unlock_new_inode(inode);
+ ret = isofs_read_inode(inode);
+ if (ret < 0) {
+ iget_failed(inode);
+ inode = ERR_PTR(ret);
+ } else {
+ unlock_new_inode(inode);
+ }
}

return inode;

2007-10-10 21:51:23

by David Howells

[permalink] [raw]
Subject: [PATCH 20/31] IGET: Stop JFFS2 from using iget() and read_inode() [try #3]

Stop the JFFS2 filesystem from using iget() and read_inode(). Replace
jffs2_read_inode() with jffs2_iget(), and call that instead of iget().
jffs2_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

jffs2_do_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
---

fs/jffs2/dir.c | 6 +++--
fs/jffs2/fs.c | 56 ++++++++++++++++++++++++++++++++-------------------
fs/jffs2/os-linux.h | 2 +-
fs/jffs2/super.c | 1 -
4 files changed, 39 insertions(+), 26 deletions(-)

diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index c1dfca3..ca0add3 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -101,10 +101,10 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
ino = fd->ino;
up(&dir_f->sem);
if (ino) {
- inode = iget(dir_i->i_sb, ino);
- if (!inode) {
+ inode = jffs2_iget(dir_i->i_sb, ino);
+ if (IS_ERR(inode)) {
printk(KERN_WARNING "iget() failed for ino #%u\n", ino);
- return (ERR_PTR(-EIO));
+ return ERR_CAST(inode);
}
}

diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 8bc727b..900be8b 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -227,16 +227,23 @@ void jffs2_clear_inode (struct inode *inode)
jffs2_do_clear_inode(c, f);
}

-void jffs2_read_inode (struct inode *inode)
+struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
{
struct jffs2_inode_info *f;
struct jffs2_sb_info *c;
struct jffs2_raw_inode latest_node;
union jffs2_device_node jdev;
+ struct inode *inode;
dev_t rdev = 0;
int ret;

- D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
+ D1(printk(KERN_DEBUG "jffs2_iget(): ino == %lu\n", ino));
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;

f = JFFS2_INODE_INFO(inode);
c = JFFS2_SB_INFO(inode->i_sb);
@@ -247,9 +254,9 @@ void jffs2_read_inode (struct inode *inode)
ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);

if (ret) {
- make_bad_inode(inode);
up(&f->sem);
- return;
+ iget_failed(inode);
+ return ERR_PTR(ret);
}
inode->i_mode = jemode_to_cpu(latest_node.mode);
inode->i_uid = je16_to_cpu(latest_node.uid);
@@ -300,19 +307,14 @@ void jffs2_read_inode (struct inode *inode)
if (f->metadata->size != sizeof(jdev.old) &&
f->metadata->size != sizeof(jdev.new)) {
printk(KERN_NOTICE "Device node has strange size %d\n", f->metadata->size);
- up(&f->sem);
- jffs2_do_clear_inode(c, f);
- make_bad_inode(inode);
- return;
+ goto error_io;
}
D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
- if (jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size) < 0) {
+ ret = jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size);
+ if (ret < 0) {
/* Eep */
printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
- up(&f->sem);
- jffs2_do_clear_inode(c, f);
- make_bad_inode(inode);
- return;
+ goto error;
}
if (f->metadata->size == sizeof(jdev.old))
rdev = old_decode_dev(je16_to_cpu(jdev.old));
@@ -332,6 +334,16 @@ void jffs2_read_inode (struct inode *inode)
up(&f->sem);

D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
+ unlock_new_inode(inode);
+ return inode;
+
+error_io:
+ ret = -EIO;
+error:
+ up(&f->sem);
+ jffs2_do_clear_inode(c, f);
+ iget_failed(inode);
+ return ERR_PTR(ret);
}

void jffs2_dirty_inode(struct inode *inode)
@@ -511,15 +523,16 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
if ((ret = jffs2_do_mount_fs(c)))
goto out_inohash;

- ret = -EINVAL;
-
D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inode\n"));
- root_i = iget(sb, 1);
- if (is_bad_inode(root_i)) {
+ root_i = jffs2_iget(sb, 1);
+ if (IS_ERR(root_i)) {
D1(printk(KERN_WARNING "get root inode failed\n"));
- goto out_root_i;
+ ret = PTR_ERR(root_i);
+ goto out_root;
}

+ ret = -ENOMEM;
+
D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n"));
sb->s_root = d_alloc_root(root_i);
if (!sb->s_root)
@@ -535,6 +548,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)

out_root_i:
iput(root_i);
+out_root:
jffs2_free_ino_caches(c);
jffs2_free_raw_node_refs(c);
if (jffs2_blocks_use_vmalloc(c))
@@ -604,9 +618,9 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
jffs2_do_unlink() would need the alloc_sem and we have it.
Just iget() it, and if read_inode() is necessary that's OK.
*/
- inode = iget(OFNI_BS_2SFFJ(c), inum);
- if (!inode)
- return ERR_PTR(-ENOMEM);
+ inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
}
if (is_bad_inode(inode)) {
printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n",
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 80daea9..c1ca2f9 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -174,7 +174,7 @@ extern const struct inode_operations jffs2_symlink_inode_operations;

/* fs.c */
int jffs2_setattr (struct dentry *, struct iattr *);
-void jffs2_read_inode (struct inode *);
+struct inode *jffs2_iget(struct super_block *, unsigned long);
void jffs2_clear_inode (struct inode *);
void jffs2_dirty_inode(struct inode *inode);
struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index be2b70c..d7d2ff6 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -65,7 +65,6 @@ static const struct super_operations jffs2_super_operations =
{
.alloc_inode = jffs2_alloc_inode,
.destroy_inode =jffs2_destroy_inode,
- .read_inode = jffs2_read_inode,
.put_super = jffs2_put_super,
.write_super = jffs2_write_super,
.statfs = jffs2_statfs,

2007-10-10 21:51:43

by David Howells

[permalink] [raw]
Subject: [PATCH 21/31] IGET: Stop JFS from using iget() and read_inode() [try #3]

Stop the JFS filesystem from using iget() and read_inode(). Replace
jfs_read_inode() with jfs_iget(), and call that instead of iget().
jfs_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

jfs_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
Acked-by: Dave Kleikamp <[email protected]>
---

fs/jfs/inode.c | 20 ++++++++++++++++----
fs/jfs/jfs_inode.h | 2 +-
fs/jfs/namei.c | 34 ++++++++++++++--------------------
fs/jfs/super.c | 15 +++++++++------
4 files changed, 40 insertions(+), 31 deletions(-)

diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index 3467dde..5081e76 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -31,11 +31,21 @@
#include "jfs_debug.h"


-void jfs_read_inode(struct inode *inode)
+struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
{
- if (diRead(inode)) {
- make_bad_inode(inode);
- return;
+ struct inode *inode;
+ int ret;
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ ret = diRead(inode);
+ if (ret < 0) {
+ iget_failed(inode);
+ return ERR_PTR(ret);
}

if (S_ISREG(inode->i_mode)) {
@@ -55,6 +65,8 @@ void jfs_read_inode(struct inode *inode)
inode->i_op = &jfs_file_inode_operations;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
}
+ unlock_new_inode(inode);
+ return inode;
}

/*
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
index f0ec72b..71ea106 100644
--- a/fs/jfs/jfs_inode.h
+++ b/fs/jfs/jfs_inode.h
@@ -22,7 +22,7 @@ extern struct inode *ialloc(struct inode *, umode_t);
extern int jfs_fsync(struct file *, struct dentry *, int);
extern int jfs_ioctl(struct inode *, struct file *,
unsigned int, unsigned long);
-extern void jfs_read_inode(struct inode *);
+extern struct inode *jfs_iget(struct super_block *, unsigned long);
extern int jfs_commit_inode(struct inode *, int);
extern int jfs_write_inode(struct inode*, int);
extern void jfs_delete_inode(struct inode *);
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 932797b..6915a3d 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -1461,12 +1461,10 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc
}
}

- ip = iget(dip->i_sb, inum);
- if (ip == NULL || is_bad_inode(ip)) {
+ ip = jfs_iget(dip->i_sb, inum);
+ if (IS_ERR(ip)) {
jfs_err("jfs_lookup: iget failed on inum %d", (uint) inum);
- if (ip)
- iput(ip);
- return ERR_PTR(-EACCES);
+ return ERR_CAST(ip);
}

dentry = d_splice_alias(ip, dentry);
@@ -1487,12 +1485,11 @@ struct dentry *jfs_get_dentry(struct super_block *sb, void *vobjp)

if (ino == 0)
return ERR_PTR(-ESTALE);
- inode = iget(sb, ino);
- if (inode == NULL)
- return ERR_PTR(-ENOMEM);
+ inode = jfs_iget(sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);

- if (is_bad_inode(inode) ||
- (generation && inode->i_generation != generation)) {
+ if (generation && inode->i_generation != generation) {
result = ERR_PTR(-ESTALE);
goto out_iput;
}
@@ -1518,17 +1515,14 @@ struct dentry *jfs_get_parent(struct dentry *dentry)

parent_ino =
le32_to_cpu(JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot);
- inode = iget(sb, parent_ino);
- if (inode) {
- if (is_bad_inode(inode)) {
+ inode = jfs_iget(sb, parent_ino);
+ if (IS_ERR(inode)) {
+ parent = ERR_CAST(inode);
+ } else {
+ parent = d_alloc_anon(inode);
+ if (!parent) {
+ parent = ERR_PTR(-ENOMEM);
iput(inode);
- parent = ERR_PTR(-EACCES);
- } else {
- parent = d_alloc_anon(inode);
- if (!parent) {
- parent = ERR_PTR(-ENOMEM);
- iput(inode);
- }
}
}

diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 4b372f5..f499634 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -414,7 +414,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
struct inode *inode;
int rc;
s64 newLVSize = 0;
- int flag;
+ int flag, ret = -EINVAL;

jfs_info("In jfs_read_super: s_flags=0x%lx", sb->s_flags);

@@ -461,8 +461,10 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
* Initialize direct-mapping inode/address-space
*/
inode = new_inode(sb);
- if (inode == NULL)
+ if (inode == NULL) {
+ ret = -ENOMEM;
goto out_kfree;
+ }
inode->i_ino = 0;
inode->i_nlink = 1;
inode->i_size = sb->s_bdev->bd_inode->i_size;
@@ -494,9 +496,11 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)

sb->s_magic = JFS_SUPER_MAGIC;

- inode = iget(sb, ROOT_I);
- if (!inode || is_bad_inode(inode))
+ inode = jfs_iget(sb, ROOT_I);
+ if (IS_ERR(inode)) {
+ ret = PTR_ERR(inode);
goto out_no_root;
+ }
sb->s_root = d_alloc_root(inode);
if (!sb->s_root)
goto out_no_root;
@@ -536,7 +540,7 @@ out_kfree:
if (sbi->nls_tab)
unload_nls(sbi->nls_tab);
kfree(sbi);
- return -EINVAL;
+ return ret;
}

static void jfs_write_super_lockfs(struct super_block *sb)
@@ -720,7 +724,6 @@ out:
static const struct super_operations jfs_super_operations = {
.alloc_inode = jfs_alloc_inode,
.destroy_inode = jfs_destroy_inode,
- .read_inode = jfs_read_inode,
.dirty_inode = jfs_dirty_inode,
.write_inode = jfs_write_inode,
.delete_inode = jfs_delete_inode,

2007-10-10 21:51:58

by David Howells

[permalink] [raw]
Subject: [PATCH 22/31] IGET: Stop the MINIX filesystem from using iget() and read_inode() [try #3]

Stop the MINIX filesystem from using iget() and read_inode(). Replace
minix_read_inode() with minix_iget(), and call that instead of iget().
minix_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

minix_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
---

fs/minix/inode.c | 43 +++++++++++++++++++++++++++++--------------
fs/minix/minix.h | 1 +
fs/minix/namei.c | 7 +++----
3 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 43668d7..ee329f8 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -18,7 +18,6 @@
#include <linux/highuid.h>
#include <linux/vfs.h>

-static void minix_read_inode(struct inode * inode);
static int minix_write_inode(struct inode * inode, int wait);
static int minix_statfs(struct dentry *dentry, struct kstatfs *buf);
static int minix_remount (struct super_block * sb, int * flags, char * data);
@@ -96,7 +95,6 @@ static void destroy_inodecache(void)
static const struct super_operations minix_sops = {
.alloc_inode = minix_alloc_inode,
.destroy_inode = minix_destroy_inode,
- .read_inode = minix_read_inode,
.write_inode = minix_write_inode,
.delete_inode = minix_delete_inode,
.put_super = minix_put_super,
@@ -149,6 +147,7 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
unsigned long i, block;
struct inode *root_inode;
struct minix_sb_info *sbi;
+ int ret = -EINVAL;

sbi = kzalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
if (!sbi)
@@ -246,10 +245,13 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)

/* set up enough so that it can read an inode */
s->s_op = &minix_sops;
- root_inode = iget(s, MINIX_ROOT_INO);
- if (!root_inode || is_bad_inode(root_inode))
+ root_inode = minix_iget(s, MINIX_ROOT_INO);
+ if (IS_ERR(root_inode)) {
+ ret = PTR_ERR(root_inode);
goto out_no_root;
+ }

+ ret = -ENOMEM;
s->s_root = d_alloc_root(root_inode);
if (!s->s_root)
goto out_iput;
@@ -290,6 +292,7 @@ out_freemap:
goto out_release;

out_no_map:
+ ret = -ENOMEM;
if (!silent)
printk("MINIX-fs: can't allocate map\n");
goto out_release;
@@ -316,7 +319,7 @@ out_bad_sb:
out:
s->s_fs_info = NULL;
kfree(sbi);
- return -EINVAL;
+ return ret;
}

static int minix_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -394,7 +397,7 @@ void minix_set_inode(struct inode *inode, dev_t rdev)
/*
* The minix V1 function to read an inode.
*/
-static void V1_minix_read_inode(struct inode * inode)
+static struct inode *V1_minix_iget(struct inode * inode)
{
struct buffer_head * bh;
struct minix_inode * raw_inode;
@@ -403,8 +406,8 @@ static void V1_minix_read_inode(struct inode * inode)

raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
if (!raw_inode) {
- make_bad_inode(inode);
- return;
+ iget_failed(inode);
+ return ERR_PTR(-EIO);
}
inode->i_mode = raw_inode->i_mode;
inode->i_uid = (uid_t)raw_inode->i_uid;
@@ -420,12 +423,14 @@ static void V1_minix_read_inode(struct inode * inode)
minix_inode->u.i1_data[i] = raw_inode->i_zone[i];
minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));
brelse(bh);
+ unlock_new_inode(inode);
+ return inode;
}

/*
* The minix V2 function to read an inode.
*/
-static void V2_minix_read_inode(struct inode * inode)
+static struct inode *V2_minix_iget(struct inode * inode)
{
struct buffer_head * bh;
struct minix2_inode * raw_inode;
@@ -434,8 +439,8 @@ static void V2_minix_read_inode(struct inode * inode)

raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
if (!raw_inode) {
- make_bad_inode(inode);
- return;
+ iget_failed(inode);
+ return ERR_PTR(-EIO);
}
inode->i_mode = raw_inode->i_mode;
inode->i_uid = (uid_t)raw_inode->i_uid;
@@ -453,17 +458,27 @@ static void V2_minix_read_inode(struct inode * inode)
minix_inode->u.i2_data[i] = raw_inode->i_zone[i];
minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));
brelse(bh);
+ unlock_new_inode(inode);
+ return inode;
}

/*
* The global function to read an inode.
*/
-static void minix_read_inode(struct inode * inode)
+struct inode *minix_iget(struct super_block *sb, unsigned long ino)
{
+ struct inode *inode;
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
if (INODE_VERSION(inode) == MINIX_V1)
- V1_minix_read_inode(inode);
+ return V1_minix_iget(inode);
else
- V2_minix_read_inode(inode);
+ return V2_minix_iget(inode);
}

/*
diff --git a/fs/minix/minix.h b/fs/minix/minix.h
index 73ef84f..3ee2242 100644
--- a/fs/minix/minix.h
+++ b/fs/minix/minix.h
@@ -45,6 +45,7 @@ struct minix_sb_info {
unsigned short s_version;
};

+extern struct inode *minix_iget(struct super_block *, unsigned long);
extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
extern struct inode * minix_new_inode(const struct inode * dir, int * error);
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index f4aa7a9..3b1684a 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -54,10 +54,9 @@ static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, st

ino = minix_inode_by_name(dentry);
if (ino) {
- inode = iget(dir->i_sb, ino);
-
- if (!inode)
- return ERR_PTR(-EACCES);
+ inode = minix_iget(dir->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
}
d_add(dentry, inode);
return NULL;

2007-10-10 21:52:24

by David Howells

[permalink] [raw]
Subject: [PATCH 24/31] IGET: Stop QNX4 from using iget() and read_inode() [try #3]

Stop the QNX4 filesystem from using iget() and read_inode(). Replace
qnx4_read_inode() with qnx4_iget(), and call that instead of iget().
qnx4_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

qnx4_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
---

fs/qnx4/inode.c | 45 ++++++++++++++++++++++++++++++---------------
fs/qnx4/namei.c | 8 +++++---
include/linux/qnx4_fs.h | 1 +
3 files changed, 36 insertions(+), 18 deletions(-)

diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 1bc8d87..3eba8fe 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -125,7 +125,6 @@ static int qnx4_write_inode(struct inode *inode, int unused)
static void qnx4_put_super(struct super_block *sb);
static struct inode *qnx4_alloc_inode(struct super_block *sb);
static void qnx4_destroy_inode(struct inode *inode);
-static void qnx4_read_inode(struct inode *);
static int qnx4_remount(struct super_block *sb, int *flags, char *data);
static int qnx4_statfs(struct dentry *, struct kstatfs *);

@@ -133,7 +132,6 @@ static const struct super_operations qnx4_sops =
{
.alloc_inode = qnx4_alloc_inode,
.destroy_inode = qnx4_destroy_inode,
- .read_inode = qnx4_read_inode,
.put_super = qnx4_put_super,
.statfs = qnx4_statfs,
.remount_fs = qnx4_remount,
@@ -357,6 +355,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
struct inode *root;
const char *errmsg;
struct qnx4_sb_info *qs;
+ int ret = -EINVAL;

qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
if (!qs)
@@ -396,12 +395,14 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
}

/* does root not have inode number QNX4_ROOT_INO ?? */
- root = iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
- if (!root) {
+ root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
+ if (IS_ERR(root)) {
printk("qnx4: get inode failed\n");
+ ret = PTR_ERR(root);
goto out;
}

+ ret = -ENOMEM;
s->s_root = d_alloc_root(root);
if (s->s_root == NULL)
goto outi;
@@ -417,7 +418,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
outnobh:
kfree(qs);
s->s_fs_info = NULL;
- return -EINVAL;
+ return ret;
}

static void qnx4_put_super(struct super_block *sb)
@@ -457,29 +458,37 @@ static const struct address_space_operations qnx4_aops = {
.bmap = qnx4_bmap
};

-static void qnx4_read_inode(struct inode *inode)
+struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
{
struct buffer_head *bh;
struct qnx4_inode_entry *raw_inode;
- int block, ino;
- struct super_block *sb = inode->i_sb;
- struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
+ int block;
+ struct qnx4_inode_entry *qnx4_inode;
+ struct inode *inode;

- ino = inode->i_ino;
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ qnx4_inode = qnx4_raw_inode(inode);
inode->i_mode = 0;

QNX4DEBUG(("Reading inode : [%d]\n", ino));
if (!ino) {
- printk("qnx4: bad inode number on dev %s: %d is out of range\n",
+ printk("qnx4: bad inode number on dev %s: %lu is out of range\n",
sb->s_id, ino);
- return;
+ iget_failed(inode);
+ return ERR_PTR(-EIO);
}
block = ino / QNX4_INODES_PER_BLOCK;

if (!(bh = sb_bread(sb, block))) {
printk("qnx4: major problem: unable to read inode from dev "
"%s\n", sb->s_id);
- return;
+ iget_failed(inode);
+ return ERR_PTR(-EIO);
}
raw_inode = ((struct qnx4_inode_entry *) bh->b_data) +
(ino % QNX4_INODES_PER_BLOCK);
@@ -510,9 +519,15 @@ static void qnx4_read_inode(struct inode *inode)
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &qnx4_aops;
qnx4_i(inode)->mmu_private = inode->i_size;
- } else
- printk("qnx4: bad inode %d on dev %s\n",ino,sb->s_id);
+ } else {
+ printk("qnx4: bad inode %lu on dev %s\n",ino,sb->s_id);
+ iget_failed(inode);
+ brelse(bh);
+ return ERR_PTR(-EIO);
+ }
brelse(bh);
+ unlock_new_inode(inode);
+ return inode;
}

static struct kmem_cache *qnx4_inode_cachep;
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index 733cdf0..775eed3 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -128,10 +128,12 @@ struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nam
}
brelse(bh);

- if ((foundinode = iget(dir->i_sb, ino)) == NULL) {
+ foundinode = qnx4_iget(dir->i_sb, ino);
+ if (IS_ERR(foundinode)) {
unlock_kernel();
- QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
- return ERR_PTR(-EACCES);
+ QNX4DEBUG(("qnx4: lookup->iget -> error %ld\n",
+ PTR_ERR(foundinode)));
+ return ERR_CAST(foundinode);
}
out:
unlock_kernel();
diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h
index 19bc9b8..34a196e 100644
--- a/include/linux/qnx4_fs.h
+++ b/include/linux/qnx4_fs.h
@@ -110,6 +110,7 @@ struct qnx4_inode_info {
struct inode vfs_inode;
};

+extern struct inode *qnx4_iget(struct super_block *, unsigned long);
extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd);
extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
extern unsigned long qnx4_block_map(struct inode *inode, long iblock);

2007-10-10 21:52:40

by David Howells

[permalink] [raw]
Subject: [PATCH 23/31] IGET: Stop PROCFS from using iget() and read_inode() [try #3]

Stop the PROCFS filesystem from using iget() and read_inode(). Merge
procfs_read_inode() into procfs_get_inode(), and have that call iget_locked()
instead of iget().

Signed-off-by: David Howells <[email protected]>
---

fs/proc/inode.c | 60 ++++++++++++++++++++++++++-----------------------------
1 files changed, 28 insertions(+), 32 deletions(-)

diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 0e4d37c..7a563c5 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -78,11 +78,6 @@ static void proc_delete_inode(struct inode *inode)

struct vfsmount *proc_mnt;

-static void proc_read_inode(struct inode * inode)
-{
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-}
-
static struct kmem_cache * proc_inode_cachep;

static struct inode *proc_alloc_inode(struct super_block *sb)
@@ -135,7 +130,6 @@ static int proc_remount(struct super_block *sb, int *flags, char *data)
static const struct super_operations proc_sops = {
.alloc_inode = proc_alloc_inode,
.destroy_inode = proc_destroy_inode,
- .read_inode = proc_read_inode,
.drop_inode = generic_delete_inode,
.delete_inode = proc_delete_inode,
.statfs = simple_statfs,
@@ -408,39 +402,41 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
if (de != NULL && !try_module_get(de->owner))
goto out_mod;

- inode = iget(sb, ino);
+ inode = iget_locked(sb, ino);
if (!inode)
goto out_ino;
-
- PROC_I(inode)->fd = 0;
- PROC_I(inode)->pde = de;
- if (de) {
- if (de->mode) {
- inode->i_mode = de->mode;
- inode->i_uid = de->uid;
- inode->i_gid = de->gid;
- }
- if (de->size)
- inode->i_size = de->size;
- if (de->nlink)
- inode->i_nlink = de->nlink;
- if (de->proc_iops)
- inode->i_op = de->proc_iops;
- if (de->proc_fops) {
- if (S_ISREG(inode->i_mode)) {
+ if (inode->i_state & I_NEW) {
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ PROC_I(inode)->fd = 0;
+ PROC_I(inode)->pde = de;
+ if (de) {
+ if (de->mode) {
+ inode->i_mode = de->mode;
+ inode->i_uid = de->uid;
+ inode->i_gid = de->gid;
+ }
+ if (de->size)
+ inode->i_size = de->size;
+ if (de->nlink)
+ inode->i_nlink = de->nlink;
+ if (de->proc_iops)
+ inode->i_op = de->proc_iops;
+ if (de->proc_fops) {
+ if (S_ISREG(inode->i_mode)) {
#ifdef CONFIG_COMPAT
- if (!de->proc_fops->compat_ioctl)
- inode->i_fop =
- &proc_reg_file_ops_no_compat;
- else
+ if (!de->proc_fops->compat_ioctl)
+ inode->i_fop =
+ &proc_reg_file_ops_no_compat;
+ else
#endif
- inode->i_fop = &proc_reg_file_ops;
+ inode->i_fop = &proc_reg_file_ops;
+ }
+ else
+ inode->i_fop = de->proc_fops;
}
- else
- inode->i_fop = de->proc_fops;
}
+ unlock_new_inode(inode);
}
-
return inode;

out_ino:

2007-10-10 21:52:56

by David Howells

[permalink] [raw]
Subject: [PATCH 26/31] IGET: Stop the SYSV filesystem from using iget() and read_inode() [try #3]

Stop the SYSV filesystem from using iget() and read_inode(). Replace
sysv_read_inode() with sysv_iget(), and call that instead of iget().
sysv_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

Signed-off-by: David Howells <[email protected]>
---

fs/sysv/inode.c | 25 ++++++++++++++++---------
fs/sysv/namei.c | 6 +++---
fs/sysv/super.c | 4 ++--
fs/sysv/sysv.h | 1 +
4 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 7c4e5d3..9d512a8 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -169,20 +169,27 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
init_special_inode(inode, inode->i_mode, rdev);
}

-static void sysv_read_inode(struct inode *inode)
+struct inode *sysv_iget(struct super_block *sb, unsigned int ino)
{
- struct super_block * sb = inode->i_sb;
struct sysv_sb_info * sbi = SYSV_SB(sb);
struct buffer_head * bh;
struct sysv_inode * raw_inode;
struct sysv_inode_info * si;
- unsigned int block, ino = inode->i_ino;
+ struct inode *inode;
+ unsigned int block;

if (!ino || ino > sbi->s_ninodes) {
printk("Bad inode number on dev %s: %d is out of range\n",
- inode->i_sb->s_id, ino);
- goto bad_inode;
+ sb->s_id, ino);
+ return ERR_PTR(-EIO);
}
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
raw_inode = sysv_raw_inode(sb, ino, &bh);
if (!raw_inode) {
printk("Major problem: unable to read inode from dev %s\n",
@@ -214,11 +221,12 @@ static void sysv_read_inode(struct inode *inode)
old_decode_dev(fs32_to_cpu(sbi, si->i_data[0])));
else
sysv_set_inode(inode, 0);
- return;
+ unlock_new_inode(inode);
+ return inode;

bad_inode:
- make_bad_inode(inode);
- return;
+ iget_failed(inode);
+ return ERR_PTR(-EIO);
}

static struct buffer_head * sysv_update_inode(struct inode * inode)
@@ -328,7 +336,6 @@ static void init_once(void *p, struct kmem_cache *cachep, unsigned long flags)
const struct super_operations sysv_sops = {
.alloc_inode = sysv_alloc_inode,
.destroy_inode = sysv_destroy_inode,
- .read_inode = sysv_read_inode,
.write_inode = sysv_write_inode,
.delete_inode = sysv_delete_inode,
.put_super = sysv_put_super,
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 6bd850b..a1f1ef3 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -53,9 +53,9 @@ static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, st
ino = sysv_inode_by_name(dentry);

if (ino) {
- inode = iget(dir->i_sb, ino);
- if (!inode)
- return ERR_PTR(-EACCES);
+ inode = sysv_iget(dir->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
}
d_add(dentry, inode);
return NULL;
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
index 6f9707a..a92d104 100644
--- a/fs/sysv/super.c
+++ b/fs/sysv/super.c
@@ -332,8 +332,8 @@ static int complete_read_super(struct super_block *sb, int silent, int size)
sb->s_magic = SYSV_MAGIC_BASE + sbi->s_type;
/* set up enough so that it can read an inode */
sb->s_op = &sysv_sops;
- root_inode = iget(sb,SYSV_ROOT_INO);
- if (!root_inode || is_bad_inode(root_inode)) {
+ root_inode = sysv_iget(sb,SYSV_ROOT_INO);
+ if (IS_ERR(root_inode)) {
printk("SysV FS: get root inode failed\n");
return 0;
}
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
index 5b4fedf..71ebdbc 100644
--- a/fs/sysv/sysv.h
+++ b/fs/sysv/sysv.h
@@ -138,6 +138,7 @@ extern unsigned long sysv_count_free_blocks(struct super_block *);
extern void sysv_truncate(struct inode *);

/* inode.c */
+extern struct inode *sysv_iget(struct super_block *, unsigned int);
extern int sysv_write_inode(struct inode *, int);
extern int sysv_sync_inode(struct inode *);
extern int sysv_sync_file(struct file *, struct dentry *, int);

2007-10-10 21:53:26

by David Howells

[permalink] [raw]
Subject: [PATCH 25/31] IGET: Stop ROMFS from using iget() and read_inode() [try #3]

Stop the ROMFS filesystem from using iget() and read_inode(). Replace
romfs_read_inode() with romfs_iget(), and call that instead of iget().
romfs_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

romfs_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
---

fs/romfs/inode.c | 45 +++++++++++++++++++++++++++++++--------------
1 files changed, 31 insertions(+), 14 deletions(-)

diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index dae7945..5071c9a 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -84,6 +84,8 @@ struct romfs_inode_info {
struct inode vfs_inode;
};

+static struct inode *romfs_iget(struct super_block *, unsigned long);
+
/* instead of private superblock data */
static inline unsigned long romfs_maxsize(struct super_block *sb)
{
@@ -117,7 +119,7 @@ static int romfs_fill_super(struct super_block *s, void *data, int silent)
struct buffer_head *bh;
struct romfs_super_block *rsb;
struct inode *root;
- int sz;
+ int sz, ret = -EINVAL;

/* I would parse the options here, but there are none.. :) */

@@ -157,10 +159,13 @@ static int romfs_fill_super(struct super_block *s, void *data, int silent)
& ROMFH_MASK;

s->s_op = &romfs_ops;
- root = iget(s, sz);
- if (!root)
+ root = romfs_iget(s, sz);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
goto out;
+ }

+ ret = -ENOMEM;
s->s_root = d_alloc_root(root);
if (!s->s_root)
goto outiput;
@@ -173,7 +178,7 @@ outiput:
out:
brelse(bh);
outnobh:
- return -EINVAL;
+ return ret;
}

/* That's simple too. */
@@ -389,8 +394,11 @@ romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
offset = be32_to_cpu(ri.spec) & ROMFH_MASK;

- if ((inode = iget(dir->i_sb, offset)))
- goto outi;
+ inode = romfs_iget(dir->i_sb, offset);
+ if (IS_ERR(inode)) {
+ res = PTR_ERR(inode);
+ goto out;
+ }

/*
* it's a bit funky, _lookup needs to return an error code
@@ -402,7 +410,7 @@ romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
*/

out0: inode = NULL;
-outi: res = 0;
+ res = 0;
d_add (dentry, inode);

out: unlock_kernel();
@@ -478,20 +486,28 @@ static mode_t romfs_modemap[] =
S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
};

-static void
-romfs_read_inode(struct inode *i)
+static struct inode *
+romfs_iget(struct super_block *sb, unsigned long ino)
{
- int nextfh, ino;
+ int nextfh;
struct romfs_inode ri;
+ struct inode *i;
+
+ ino &= ROMFH_MASK;
+ i = iget_locked(sb, ino);
+ if (!i)
+ return ERR_PTR(-ENOMEM);
+ if (!(i->i_state & I_NEW))
+ return i;

- ino = i->i_ino & ROMFH_MASK;
i->i_mode = 0;

/* Loop for finding the real hard link */
for(;;) {
if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
- printk("romfs: read error for inode 0x%x\n", ino);
- return;
+ printk("romfs: read error for inode 0x%lx\n", ino);
+ iget_failed(i);
+ return ERR_PTR(-EIO);
}
/* XXX: do romfs_checksum here too (with name) */

@@ -548,6 +564,8 @@ romfs_read_inode(struct inode *i)
init_special_inode(i, ino,
MKDEV(nextfh>>16,nextfh&0xffff));
}
+ unlock_new_inode(i);
+ return i;
}

static struct kmem_cache * romfs_inode_cachep;
@@ -599,7 +617,6 @@ static int romfs_remount(struct super_block *sb, int *flags, char *data)
static const struct super_operations romfs_ops = {
.alloc_inode = romfs_alloc_inode,
.destroy_inode = romfs_destroy_inode,
- .read_inode = romfs_read_inode,
.statfs = romfs_statfs,
.remount_fs = romfs_remount,
};

2007-10-10 21:53:42

by David Howells

[permalink] [raw]
Subject: [PATCH 27/31] IGET: Stop UFS from using iget() and read_inode() [try #3]

Stop the UFS filesystem from using iget() and read_inode(). Replace
ufs_read_inode() with ufs_iget(), and call that instead of iget().
ufs_iget() then uses iget_locked() directly and returns a proper error code
instead of an inode in the event of an error.

ufs_fill_super() returns any error incurred when getting the root inode
instead of EINVAL.

Signed-off-by: David Howells <[email protected]>
---

fs/ufs/inode.c | 34 ++++++++++++++++++++--------------
fs/ufs/namei.c | 6 +++---
fs/ufs/super.c | 14 +++++++++-----
include/linux/ufs_fs.h | 2 +-
4 files changed, 33 insertions(+), 23 deletions(-)

diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index f18b791..d7c2d3c 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -698,26 +698,30 @@ static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode)
return 0;
}

-void ufs_read_inode(struct inode * inode)
+struct inode *ufs_iget (struct super_block *sb, unsigned long ino)
{
- struct ufs_inode_info *ufsi = UFS_I(inode);
- struct super_block * sb;
- struct ufs_sb_private_info * uspi;
+ struct ufs_inode_info *ufsi;
+ struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
struct buffer_head * bh;
+ struct inode *inode;
int err;

- UFSD("ENTER, ino %lu\n", inode->i_ino);
-
- sb = inode->i_sb;
- uspi = UFS_SB(sb)->s_uspi;
+ UFSD("ENTER, ino %lu\n", ino);

- if (inode->i_ino < UFS_ROOTINO ||
- inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
+ if (ino < UFS_ROOTINO || ino > (uspi->s_ncg * uspi->s_ipg)) {
ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n",
- inode->i_ino);
- goto bad_inode;
+ ino);
+ return ERR_PTR(-EIO);
}

+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ ufsi = UFS_I(inode);
+
bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino));
if (!bh) {
ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n",
@@ -749,10 +753,12 @@ void ufs_read_inode(struct inode * inode)
brelse(bh);

UFSD("EXIT\n");
- return;
+ unlock_new_inode(inode);
+ return inode;

bad_inode:
- make_bad_inode(inode);
+ iget_failed(inode);
+ return ERR_PTR(-EIO);
}

static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode)
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index a059ccd..a00cec1 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -57,10 +57,10 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru
lock_kernel();
ino = ufs_inode_by_name(dir, dentry);
if (ino) {
- inode = iget(dir->i_sb, ino);
- if (!inode) {
+ inode = ufs_iget(dir->i_sb, ino);
+ if (IS_ERR(inode)) {
unlock_kernel();
- return ERR_PTR(-EACCES);
+ return ERR_CAST(inode);
}
}
unlock_kernel();
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 38eb0b7..8e157ab 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -613,6 +613,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
unsigned block_size, super_block_size;
unsigned flags;
unsigned super_block_offset;
+ int ret = -EINVAL;

uspi = NULL;
ubh = NULL;
@@ -1026,12 +1027,16 @@ magic_found:
uspi->s_maxsymlinklen =
fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen);

- inode = iget(sb, UFS_ROOTINO);
- if (!inode || is_bad_inode(inode))
+ inode = ufs_iget(sb, UFS_ROOTINO);
+ if (IS_ERR(inode)) {
+ ret = PTR_ERR(inode);
goto failed;
+ }
sb->s_root = d_alloc_root(inode);
- if (!sb->s_root)
+ if (!sb->s_root) {
+ ret = -ENOMEM;
goto dalloc_failed;
+ }

ufs_setup_cstotal(sb);
/*
@@ -1053,7 +1058,7 @@ failed:
kfree(sbi);
sb->s_fs_info = NULL;
UFSD("EXIT (FAILED)\n");
- return -EINVAL;
+ return ret;

failed_nomem:
UFSD("EXIT (NOMEM)\n");
@@ -1264,7 +1269,6 @@ static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t,
static const struct super_operations ufs_super_ops = {
.alloc_inode = ufs_alloc_inode,
.destroy_inode = ufs_destroy_inode,
- .read_inode = ufs_read_inode,
.write_inode = ufs_write_inode,
.delete_inode = ufs_delete_inode,
.put_super = ufs_put_super,
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index daeba22..2a61fa3 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -979,7 +979,7 @@ extern void ufs_free_inode (struct inode *inode);
extern struct inode * ufs_new_inode (struct inode *, int);

/* inode.c */
-extern void ufs_read_inode (struct inode *);
+extern struct inode *ufs_iget (struct super_block *, unsigned long);
extern void ufs_put_inode (struct inode *);
extern int ufs_write_inode (struct inode *, int);
extern int ufs_sync_inode (struct inode *);

2007-10-10 21:54:03

by David Howells

[permalink] [raw]
Subject: [PATCH 28/31] IGET: Stop OPENPROMFS from using iget() and read_inode() [try #3]

Stop the OPENPROMFS filesystem from using iget() and read_inode(). Replace
openpromfs_read_inode() with openpromfs_iget(), and call that instead of
iget(). openpromfs_iget() then uses iget_locked() directly and returns a
proper error code instead of an inode in the event of an error.

openpromfs_fill_super() returns any error incurred when getting the root inode
instead of ENOMEM (not that it currently incurs any other error).

Signed-off-by: David Howells <[email protected]>
---

fs/openpromfs/inode.c | 45 ++++++++++++++++++++++++++++++---------------
1 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index dd86be2..9c6017b 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -38,6 +38,8 @@ struct op_inode_info {
union op_inode_data u;
};

+static struct inode *openprom_iget(struct super_block *sb, ino_t ino);
+
static inline struct op_inode_info *OP_I(struct inode *inode)
{
return container_of(inode, struct op_inode_info, vfs_inode);
@@ -226,10 +228,10 @@ static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry
return ERR_PTR(-ENOENT);

found:
- inode = iget(dir->i_sb, ino);
+ inode = openprom_iget(dir->i_sb, ino);
mutex_unlock(&op_mutex);
- if (!inode)
- return ERR_PTR(-EINVAL);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
ent_oi = OP_I(inode);
ent_oi->type = ent_type;
ent_oi->u = ent_data;
@@ -348,14 +350,23 @@ static void openprom_destroy_inode(struct inode *inode)
kmem_cache_free(op_inode_cachep, OP_I(inode));
}

-static void openprom_read_inode(struct inode * inode)
+static struct inode *openprom_iget(struct super_block *sb, ino_t ino)
{
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- if (inode->i_ino == OPENPROM_ROOT_INO) {
- inode->i_op = &openprom_inode_operations;
- inode->i_fop = &openprom_operations;
- inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ struct inode *inode;
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (inode->i_state & I_NEW) {
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ if (inode->i_ino == OPENPROM_ROOT_INO) {
+ inode->i_op = &openprom_inode_operations;
+ inode->i_fop = &openprom_operations;
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ }
+ unlock_new_inode(inode);
}
+ return inode;
}

static int openprom_remount(struct super_block *sb, int *flags, char *data)
@@ -367,7 +378,6 @@ static int openprom_remount(struct super_block *sb, int *flags, char *data)
static const struct super_operations openprom_sops = {
.alloc_inode = openprom_alloc_inode,
.destroy_inode = openprom_destroy_inode,
- .read_inode = openprom_read_inode,
.statfs = simple_statfs,
.remount_fs = openprom_remount,
};
@@ -376,6 +386,7 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent)
{
struct inode *root_inode;
struct op_inode_info *oi;
+ int ret;

s->s_flags |= MS_NOATIME;
s->s_blocksize = 1024;
@@ -383,9 +394,11 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent)
s->s_magic = OPENPROM_SUPER_MAGIC;
s->s_op = &openprom_sops;
s->s_time_gran = 1;
- root_inode = iget(s, OPENPROM_ROOT_INO);
- if (!root_inode)
+ root_inode = openprom_iget(s, OPENPROM_ROOT_INO);
+ if (IS_ERR(root_inode)) {
+ ret = PTR_ERR(root_inode);
goto out_no_root;
+ }

oi = OP_I(root_inode);
oi->type = op_inode_node;
@@ -393,13 +406,15 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent)

s->s_root = d_alloc_root(root_inode);
if (!s->s_root)
- goto out_no_root;
+ goto out_no_root_dentry;
return 0;

+out_no_root_dentry:
+ iput(root_inode);
+ ret = -ENOMEM;
out_no_root:
printk("openprom_fill_super: get root inode failed\n");
- iput(root_inode);
- return -ENOMEM;
+ return ret;
}

static int openprom_get_sb(struct file_system_type *fs_type,

2007-10-10 21:54:25

by David Howells

[permalink] [raw]
Subject: [PATCH 30/31] IGET: Stop HPPFS from using iget() and read_inode() [try #3]

Stop the HPPFS filesystem from using iget() and read_inode(). Provide an
hppfs_iget(), and call that instead of iget(). hppfs_iget() then uses
iget_locked() directly and returns a proper error code instead of an inode in
the event of an error.

hppfs_fill_sb_common() returns any error incurred when getting the root inode
instead of EINVAL.

Note that the contents of hppfs_kern.c need to be examined:

(*) The HPPFS inode retains a pointer to the proc dentry it is shadowing, but
whilst it does appear to retain a reference to it, it doesn't appear to
destroy the reference if the inode goes away.

(*) hppfs_iget() should perhaps subsume init_inode() and hppfs_read_inode().

(*) It would appear that all hppfs inodes are the same inode because iget()
was being called with inode number 0, which forms the lookup key.

Signed-off-by: David Howells <[email protected]>
---

fs/hppfs/hppfs_kern.c | 27 ++++++++++++++++++++++-----
1 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
index affb741..a1e1f0f 100644
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs_kern.c
@@ -155,6 +155,20 @@ static void hppfs_read_inode(struct inode *ino)
ino->i_blocks = proc_ino->i_blocks;
}

+static struct inode *hppfs_iget(struct super_block *sb)
+{
+ struct inode *inode;
+
+ inode = iget_locked(sb, 0);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (inode->i_state & I_NEW) {
+ hppfs_read_inode(inode);
+ unlock_new_inode(inode);
+ }
+ return inode;
+}
+
static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
struct nameidata *nd)
{
@@ -190,9 +204,11 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
if(IS_ERR(proc_dentry))
return(proc_dentry);

- inode = iget(ino->i_sb, 0);
- if(inode == NULL)
+ inode = hppfs_iget(ino->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
goto out_dput;
+ }

err = init_inode(inode, proc_dentry);
if(err)
@@ -652,7 +668,6 @@ static void hppfs_destroy_inode(struct inode *inode)
static const struct super_operations hppfs_sbops = {
.alloc_inode = hppfs_alloc_inode,
.destroy_inode = hppfs_destroy_inode,
- .read_inode = hppfs_read_inode,
.delete_inode = hppfs_delete_inode,
.statfs = hppfs_statfs,
};
@@ -745,9 +760,11 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
sb->s_magic = HPPFS_SUPER_MAGIC;
sb->s_op = &hppfs_sbops;

- root_inode = iget(sb, 0);
- if(root_inode == NULL)
+ root_inode = hppfs_iget(sb);
+ if (IS_ERR(root_inode)) {
+ err = PTR_ERR(root_inode);
goto out;
+ }

err = init_inode(root_inode, proc_sb->s_root);
if(err)

2007-10-10 21:54:44

by David Howells

[permalink] [raw]
Subject: [PATCH 29/31] IGET: Stop HOSTFS from using iget() and read_inode() [try #3]

Stop the HOSTFS filesystem from using iget() and read_inode(). Provide
hostfs_iget(), and call that instead of iget(). hostfs_iget() then uses
iget_locked() directly and returns a proper error code instead of an inode in
the event of an error.

hostfs_fill_sb_common() returns any error incurred when getting the root inode
instead of EINVAL.

Note that the contents of hostfs_kern.c need to be examined:

(*) hostfs_iget() should perhaps subsume init_inode() and hostfs_read_inode().

(*) It would appear that all hostfs inodes are the same inode because iget()
was being called with inode number 0 - which forms the lookup key.

Signed-off-by: David Howells <[email protected]>
---

fs/hostfs/hostfs_kern.c | 58 ++++++++++++++++++++++++++++++++---------------
1 files changed, 39 insertions(+), 19 deletions(-)

diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index c778620..c6a456a 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -208,7 +208,7 @@ static char *follow_link(char *link)
return ERR_PTR(n);
}

-static int read_inode(struct inode *ino)
+static int hostfs_read_inode(struct inode *ino)
{
char *name;
int err = 0;
@@ -238,6 +238,25 @@ static int read_inode(struct inode *ino)
return err;
}

+static struct inode *hostfs_iget(struct super_block *sb)
+{
+ struct inode *inode;
+ long ret;
+
+ inode = iget_locked(sb, 0);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (inode->i_state & I_NEW) {
+ ret = hostfs_read_inode(inode);
+ if (ret < 0) {
+ iget_failed(inode);
+ return ERR_PTR(ret);
+ }
+ unlock_new_inode(inode);
+ }
+ return inode;
+}
+
int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
{
/* do_statfs uses struct statfs64 internally, but the linux kernel
@@ -305,17 +324,11 @@ static void hostfs_destroy_inode(struct inode *inode)
kfree(HOSTFS_I(inode));
}

-static void hostfs_read_inode(struct inode *inode)
-{
- read_inode(inode);
-}
-
static const struct super_operations hostfs_sbops = {
.alloc_inode = hostfs_alloc_inode,
.drop_inode = generic_delete_inode,
.delete_inode = hostfs_delete_inode,
.destroy_inode = hostfs_destroy_inode,
- .read_inode = hostfs_read_inode,
.statfs = hostfs_statfs,
};

@@ -584,9 +597,11 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
char *name;
int error, fd;

- error = -ENOMEM;
- inode = iget(dir->i_sb, 0);
- if(inode == NULL) goto out;
+ inode = hostfs_iget(dir->i_sb);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ goto out;
+ }

error = init_inode(inode, dentry);
if(error)
@@ -627,10 +642,11 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
char *name;
int err;

- err = -ENOMEM;
- inode = iget(ino->i_sb, 0);
- if(inode == NULL)
+ inode = hostfs_iget(ino->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
goto out;
+ }

err = init_inode(inode, dentry);
if(err)
@@ -748,11 +764,13 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
struct inode *inode;
char *name;
- int err = -ENOMEM;
+ int err;

- inode = iget(dir->i_sb, 0);
- if(inode == NULL)
+ inode = hostfs_iget(dir->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
goto out;
+ }

err = init_inode(inode, dentry);
if(err)
@@ -973,9 +991,11 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)

sprintf(host_root_path, "%s/%s", root_ino, req_root);

- root_inode = iget(sb, 0);
- if(root_inode == NULL)
+ root_inode = hostfs_iget(sb);
+ if (IS_ERR(root_inode)) {
+ err = PTR_ERR(root_inode);
goto out_free;
+ }

err = init_inode(root_inode, NULL);
if(err)
@@ -991,7 +1011,7 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
if(sb->s_root == NULL)
goto out_put;

- err = read_inode(root_inode);
+ err = hostfs_read_inode(root_inode);
if(err){
/* No iput in this case because the dput does that for us */
dput(sb->s_root);

2007-10-10 21:55:00

by David Howells

[permalink] [raw]
Subject: [PATCH 31/31] IGET: Remove iget() and the read_inode() super op as being obsolete [try #3]

Remove the old iget() call and the read_inode() superblock operation it uses
as these are really obsolete, and the use of read_inode() does not produce
proper error handling (no distinction between ENOMEM and EIO when marking
an inode bad).

Furthermore, this removes the temptation to use iget() to find an inode by
number in a filesystem from code outside that filesystem.

iget_locked() should be used instead. A new function is added in an earlier
patch (iget_failed) that is to be called to mark an inode as bad, unlock it and
release it should the get routine fail.
Mark iget() and read_inode() as being obsolete and remove references to them
from the documentation.


Typically a filesystem will be modified such that the read_inode function
becomes an internal iget function, for example the following:

void thingyfs_read_inode(struct inode *inode)
{
...
}

would be changed into something like:

struct inode *thingyfs_iget(struct super_block *sp, unsigned long ino)
{
struct inode *inode;
int ret;

inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW))
return inode;

...
unlock_new_inode(inode);
return inode;
error:
iget_failed(inode);
return ERR_PTR(ret);
}

and then thingyfs_iget() would be called rather than iget(), for example:

ret = -EINVAL;
inode = iget(sb, ino);
if (!inode || is_bad_inode(inode))
goto error;

becomes:

inode = thingyfs_iget(sb, ino);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
goto error;
}

Note that is_bad_inode() does not need to be called. The error returned by
thingyfs_iget() should render it unnecessary.

Signed-off-by: David Howells <[email protected]>
---

Documentation/filesystems/Exporting | 5 -----
Documentation/filesystems/Locking | 3 ---
Documentation/filesystems/porting | 12 ++++++------
Documentation/filesystems/vfs.txt | 17 +++--------------
fs/inode.c | 4 ----
include/linux/fs.h | 14 --------------
6 files changed, 9 insertions(+), 46 deletions(-)

diff --git a/Documentation/filesystems/Exporting b/Documentation/filesystems/Exporting
index 31047e0..22ce3b2 100644
--- a/Documentation/filesystems/Exporting
+++ b/Documentation/filesystems/Exporting
@@ -144,11 +144,6 @@ filesystem:
decode_fh passes two datums through find_exported_dentry. One that
should be used to identify the target object, and one that can be
used to identify the object's parent, should that be necessary.
- The default get_dentry function assumes that the datum contains an
- inode number and a generation number, and it attempts to get the
- inode using "iget" and check it's validity by matching the
- generation number. A filesystem should only depend on the default
- if iget can safely be used this way.

If decode_fh and/or encode_fh are left as NULL, then default
implementations are used. These defaults are suitable for ext2 and
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index f0f8258..d155893 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -90,7 +90,6 @@ of the locking scheme for directory operations.
prototypes:
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);
- void (*read_inode) (struct inode *);
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
@@ -114,7 +113,6 @@ locking rules:
BKL s_lock s_umount
alloc_inode: no no no
destroy_inode: no
-read_inode: no (see below)
dirty_inode: no (must not sleep)
write_inode: no
put_inode: no
@@ -133,7 +131,6 @@ show_options: no (vfsmount->sem)
quota_read: no no no (see below)
quota_write: no no no (see below)

-->read_inode() is not a method - it's a callback used in iget().
->remount_fs() will have the s_umount lock if it's already mounted.
When called from get_sb_single, it does NOT have the s_umount lock.
->quota_read() and ->quota_write() functions are both guaranteed to
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 3b0fb22..93d9362 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -34,8 +34,8 @@ FOO_I(inode) (see in-tree filesystems for examples).

Make them ->alloc_inode and ->destroy_inode in your super_operations.

-Keep in mind that now you need explicit initialization of private data -
-typically in ->read_inode() and after getting an inode from new_inode().
+Keep in mind that now you need explicit initialization of private data
+typically between calling iget_locked() and unlocking the inode.

At some point that will become mandatory.

@@ -173,10 +173,10 @@ should be a non-blocking function that initializes those parts of a
newly created inode to allow the test function to succeed. 'data' is
passed as an opaque value to both test and set functions.

-When the inode has been created by iget5_locked(), it will be returned with
-the I_NEW flag set and will still be locked. read_inode has not been
-called so the file system still has to finalize the initialization. Once
-the inode is initialized it must be unlocked by calling unlock_new_inode().
+When the inode has been created by iget5_locked(), it will be returned with the
+I_NEW flag set and will still be locked. The filesystem then needs to finalize
+the initialization. Once the inode is initialized it must be unlocked by
+calling unlock_new_inode().

The filesystem is responsible for setting (and possibly testing) i_ino
when appropriate. There is also a simpler iget_locked function that
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 045f3e0..133bc88 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -203,8 +203,6 @@ struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);

- void (*read_inode) (struct inode *);
-
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
@@ -242,15 +240,6 @@ or bottom half).
->alloc_inode was defined and simply undoes anything done by
->alloc_inode.

- read_inode: this method is called to read a specific inode from the
- mounted filesystem. The i_ino member in the struct inode is
- initialized by the VFS to indicate which inode to read. Other
- members are filled in by this method.
-
- You can set this to NULL and use iget5_locked() instead of iget()
- to read inodes. This is necessary for filesystems for which the
- inode number is not sufficient to identify an inode.
-
dirty_inode: this method is called by the VFS to mark an inode dirty.

write_inode: this method is called when the VFS needs to write an
@@ -308,9 +297,9 @@ or bottom half).

quota_write: called by the VFS to write to filesystem quota file.

-The read_inode() method is responsible for filling in the "i_op"
-field. This is a pointer to a "struct inode_operations" which
-describes the methods that can be performed on individual inodes.
+Whoever sets up the inode is responsible for filling in the "i_op" field. This
+is a pointer to a "struct inode_operations" which describes the methods that
+can be performed on individual inodes.


The Inode Object
diff --git a/fs/inode.c b/fs/inode.c
index 29f5068..8c156c6 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -901,8 +901,6 @@ EXPORT_SYMBOL(ilookup);
* @set: callback used to initialize a new struct inode
* @data: opaque data pointer to pass to @test and @set
*
- * This is iget() without the read_inode() portion of get_new_inode().
- *
* iget5_locked() uses ifind() to search for the inode specified by @hashval
* and @data in the inode cache and if present it is returned with an increased
* reference count. This is a generalized version of iget_locked() for file
@@ -939,8 +937,6 @@ EXPORT_SYMBOL(iget5_locked);
* @sb: super block of file system
* @ino: inode number to get
*
- * This is iget() without the read_inode() portion of get_new_inode_fast().
- *
* iget_locked() uses ifind_fast() to search for the inode specified by @ino in
* the inode cache and if present it is returned with an increased reference
* count. This is for file systems where the inode number is sufficient for
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c24d433..42aabc1 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1181,8 +1181,6 @@ struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);

- void (*read_inode) (struct inode *);
-
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
@@ -1618,18 +1616,6 @@ extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*te
extern struct inode * iget_locked(struct super_block *, unsigned long);
extern void unlock_new_inode(struct inode *);

-static inline struct inode *iget(struct super_block *sb, unsigned long ino)
-{
- struct inode *inode = iget_locked(sb, ino);
-
- if (inode && (inode->i_state & I_NEW)) {
- sb->s_op->read_inode(inode);
- unlock_new_inode(inode);
- }
-
- return inode;
-}
-
extern void __iget(struct inode * inode);
extern void iget_failed(struct inode *);
extern void clear_inode(struct inode *);

2007-10-11 00:54:50

by Roel Kluin

[permalink] [raw]
Subject: Re: [PATCH 09/31] IGET: Stop BFS from using iget() and read_inode() [try #3]

It is very well possible that I misunderstand the locking order here,
but FWIW:

David Howells wrote:
> diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
> index f346eb1..76798c9 100644
> --- a/fs/bfs/inode.c
> +++ b/fs/bfs/inode.c
> @@ -32,25 +32,29 @@ MODULE_LICENSE("GPL");
>
> void dump_imap(const char *prefix, struct super_block * s);
>
> -static void bfs_read_inode(struct inode * inode)
> +struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
> {
> - unsigned long ino = inode->i_ino;
> struct bfs_inode * di;
> struct buffer_head * bh;
> + struct inode *inode;
> int block, off;
>
> + inode = iget_locked(sb, ino);

after this

> + if (IS_ERR(inode))
> + return ERR_PTR(-ENOMEM);
> + if (!(inode->i_state & I_NEW))
> + return inode;

Don't you have to unlock_new_inode(inode) before returning?

> +
> if (ino < BFS_ROOT_INO || ino > BFS_SB(inode->i_sb)->si_lasti) {
> printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino);
> - make_bad_inode(inode);
> - return;
> + goto error;
> }
>
> block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
> bh = sb_bread(inode->i_sb, block);
> if (!bh) {
> printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id, ino);
> - make_bad_inode(inode);
> - return;
> + goto error;
> }
>
> off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
> @@ -85,6 +89,12 @@ static void bfs_read_inode(struct inode * inode)
> BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino); /* can be 0 so we store a copy */
>
> brelse(bh);
> + unlock_new_inode(inode);
> + return inode;
> +
> +error:

and also here?

> + iget_failed(inode);
> + return ERR_PTR(-EIO);
> }

2007-10-11 07:40:19

by David Howells

[permalink] [raw]
Subject: Re: [PATCH 09/31] IGET: Stop BFS from using iget() and read_inode() [try #3]

Roel Kluin <[email protected]> wrote:

> > + if (IS_ERR(inode))
> > + return ERR_PTR(-ENOMEM);
> > + if (!(inode->i_state & I_NEW))
> > + return inode;
>
> Don't you have to unlock_new_inode(inode) before returning?

In the first case, no because an OOM error was returned rather than an inode,
and in the second case, no because an extant non-locked inode was returned.

The inode is only returned locked by iget_locked() if it is also new - in
which case we don't return in either of the above two statements.

> > +error:
>
> and also here?
>
> > + iget_failed(inode);
> > + return ERR_PTR(-EIO);

Take a look at what iget_failed() does (patch #3):

void iget_failed(struct inode *inode)
{
make_bad_inode(inode);
unlock_new_inode(inode);
iput(inode);
}

David