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
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.
David
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 *);
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);
}
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);
}
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;
}
Signed-off-by: David Howells <[email protected]>
---
Documentation/filesystems/Exporting | 5 -----
Documentation/filesystems/Locking | 3 ---
Documentation/filesystems/vfs.txt | 16 +++++-----------
fs/inode.c | 16 ++++++++++++++++
include/linux/fs.h | 16 +++-------------
5 files changed, 24 insertions(+), 32 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/vfs.txt b/Documentation/filesystems/vfs.txt
index 045f3e0..63c7e91 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -242,14 +242,8 @@ 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.
+ read_inode: deprecated, do not use. Use iget_locked() instead of iget() and
+ return a proper error value.
dirty_inode: this method is called by the VFS to mark an inode dirty.
@@ -308,9 +302,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..f78db20 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1427,3 +1427,19 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
mode);
}
EXPORT_SYMBOL(init_special_inode);
+
+/*
+ * old deprecated inode creator
+ */
+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;
+}
+EXPORT_SYMBOL(iget);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c24d433..dfa07d2 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1181,7 +1181,7 @@ struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);
- void (*read_inode) (struct inode *);
+ void (*read_inode) (struct inode *) __deprecated;
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
@@ -1618,18 +1618,8 @@ 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 struct inode *iget(struct super_block *sb, unsigned long ino)
+ __deprecated;
extern void __iget(struct inode * inode);
extern void iget_failed(struct inode *);
extern void clear_inode(struct inode *);
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 | 7 +++----
fs/affs/super.c | 12 +++++++++---
5 files changed, 30 insertions(+), 17 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 a42143c..4c38282 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -223,10 +223,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
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;
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]>
---
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..a460b28 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_PTR(PTR_ERR(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
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..dfa0246 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_PTR(PTR_ERR(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,
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)
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..7ad3694 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_PTR(PTR_ERR(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_PTR(PTR_ERR(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);
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]>
---
fs/ext2/ext2.h | 2 +-
fs/ext2/inode.c | 26 +++++++++++++++++++-------
fs/ext2/namei.c | 12 ++++++------
fs/ext2/super.c | 32 ++++++++++++++++++--------------
4 files changed, 44 insertions(+), 28 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..d8fb795 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1074,18 +1074,28 @@ 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
+
+ raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);
if (IS_ERR(raw_inode))
goto bad_inode;
@@ -1111,6 +1121,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 +1191,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..2dfdeaa 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_PTR(PTR_ERR(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_PTR(PTR_ERR(inode));
parent = d_alloc_anon(inode);
if (!parent) {
iput(inode);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 639a32c..78641e3 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_PTR(PTR_ERR(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,
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]>
---
fs/ext3/ialloc.c | 15 ++++++++++-----
fs/ext3/inode.c | 25 +++++++++++++++++++------
fs/ext3/namei.c | 25 +++++++------------------
fs/ext3/resize.c | 7 +++----
fs/ext3/super.c | 41 +++++++++++++++++++++++------------------
include/linux/ext3_fs.h | 2 +-
6 files changed, 63 insertions(+), 52 deletions(-)
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index e45dbd6..c2f0a0d 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -646,7 +646,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
unsigned long block_group;
int bit;
struct buffer_head *bitmap_bh = NULL;
- struct inode *inode = NULL;
+ struct inode *inode = ERR_PTR(-EIO);
/* Error cases - e2fsck has already cleaned up for us */
if (ino > max_ino) {
@@ -668,9 +668,14 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
* 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) {
+ if (ext3_test_bit(bit, bitmap_bh->b_data))
+ goto out;
+
+ inode = ext3_iget(sb, ino);
+ if (IS_ERR(inode))
+ goto out;
+
+ if (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",
@@ -688,7 +693,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
if (inode && inode->i_nlink == 0)
inode->i_blocks = 0;
iput(inode);
- inode = NULL;
+ inode = ERR_PTR(-EIO);
}
out:
brelse(bitmap_bh);
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..78bfab5 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);
}
+ inode = ext3_iget(dir->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_PTR(PTR_ERR(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);
}
+ inode = ext3_iget(child->d_inode->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_PTR(PTR_ERR(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..e06bfac 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_PTR(PTR_ERR(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,25 @@ 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);
+ if (PTR_ERR(root) == -ENOMEM)
+ ret = -ENOMEM;
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 +1839,7 @@ out_fail:
sb->s_fs_info = NULL;
kfree(sbi);
lock_kernel();
- return -EINVAL;
+ return ret;
}
/*
@@ -1870,8 +1875,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 +1889,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 *);
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]>
---
fs/ext4/ialloc.c | 13 +++++++++----
fs/ext4/inode.c | 25 +++++++++++++++++++------
fs/ext4/namei.c | 25 +++++++------------------
fs/ext4/resize.c | 7 +++----
fs/ext4/super.c | 36 ++++++++++++++++++++----------------
include/linux/ext4_fs.h | 2 +-
6 files changed, 59 insertions(+), 49 deletions(-)
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 427f830..8bb63f2 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -682,9 +682,14 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
* 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) {
+ if (ext4_test_bit(bit, bitmap_bh->b_data))
+ goto out;
+
+ inode = ext4_iget(sb, ino);
+ if (IS_ERR(inode))
+ goto out;
+
+ if (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",
@@ -702,7 +707,7 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
if (inode && inode->i_nlink == 0)
inode->i_blocks = 0;
iput(inode);
- inode = NULL;
+ inode = ERR_PTR(-EIO);
}
out:
brelse(bitmap_bh);
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..af98d07 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);
}
+ inode = ext4_iget(dir->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_PTR(PTR_ERR(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);
}
+ inode = ext4_iget(child->d_inode->i_sb, ino);
+ if (IS_ERR(inode))
+ return ERR_PTR(PTR_ERR(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..74bbbe0 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_PTR(PTR_ERR(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 *);
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 4baa5f2..7aa1b5f 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;
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..aefda0e 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_PTR(PTR_ERR(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_PTR(PTR_ERR(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..5e08418 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_PTR(PTR_ERR(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;
}
/*
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,
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..edcb3b0 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_PTR(PTR_ERR(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);
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;
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..19d8017 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_PTR(PTR_ERR(inode));
}
}
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 8bc727b..e8fe629 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_PTR(PTR_ERR(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,
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]>
---
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..c436c8a 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_PTR(PTR_ERR(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_PTR(PTR_ERR(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_PTR(PTR_ERR(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,
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..b991376 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_PTR(PTR_ERR(inode));
}
d_add(dentry, inode);
return NULL;
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:
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,
};
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..5e60505 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_PTR(PTR_ERR(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);
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..599d980 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_PTR(PTR_ERR(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);
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..e40726f 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_PTR(PTR_ERR(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 *);
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..09aa822 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_PTR(PTR_ERR(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,
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);
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)
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 (iget_failed)
that is to be called to mark an inode as bad, unlock it and release it should
the get routine fail.
Signed-off-by: David Howells <[email protected]>
---
Documentation/filesystems/porting | 4 ++--
Documentation/filesystems/vfs.txt | 5 -----
fs/inode.c | 16 ----------------
include/linux/fs.h | 4 ----
4 files changed, 2 insertions(+), 27 deletions(-)
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 3b0fb22..c20eae9 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 calling unlocking the inode.
At some point that will become mandatory.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 63c7e91..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,9 +240,6 @@ or bottom half).
->alloc_inode was defined and simply undoes anything done by
->alloc_inode.
- read_inode: deprecated, do not use. Use iget_locked() instead of iget() and
- return a proper error value.
-
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
diff --git a/fs/inode.c b/fs/inode.c
index f78db20..29f5068 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1427,19 +1427,3 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
mode);
}
EXPORT_SYMBOL(init_special_inode);
-
-/*
- * old deprecated inode creator
- */
-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;
-}
-EXPORT_SYMBOL(iget);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index dfa07d2..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 *) __deprecated;
-
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
@@ -1618,8 +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 *);
-extern struct inode *iget(struct super_block *sb, unsigned long ino)
- __deprecated;
extern void __iget(struct inode * inode);
extern void iget_failed(struct inode *);
extern void clear_inode(struct inode *);
On Mon, 1 Oct 2007, Zach Brown wrote:
>
> If you're soliciting opinions, I think I tend to prefer the feel of the
> code paths after the changes. I don't know the benefits of the change
> are worth the risk in unmaintained file systems, though.
>
> > + return ERR_PTR(PTR_ERR(inode));
>
> This caught my eye. Surely we can do better :). It seems to happen a
> few times in the patches, the instance in this patch was the first that
> I noticed.
Yeah. The above obviously *should* be the same as
return inode;
apart from a few casts. But if the casts matter, there's something else
wrong.
Linus
If you're soliciting opinions, I think I tend to prefer the feel of the
code paths after the changes. I don't know the benefits of the change
are worth the risk in unmaintained file systems, though.
> + return ERR_PTR(PTR_ERR(inode));
This caught my eye. Surely we can do better :). It seems to happen a
few times in the patches, the instance in this patch was the first that
I noticed.
- z
On Mon, Oct 01, 2007 at 10:44:59AM -0700, Linus Torvalds wrote:
> > If you're soliciting opinions, I think I tend to prefer the feel of the
> > code paths after the changes. I don't know the benefits of the change
> > are worth the risk in unmaintained file systems, though.
> >
> > > + return ERR_PTR(PTR_ERR(inode));
> >
> > This caught my eye. Surely we can do better :). It seems to happen a
> > few times in the patches, the instance in this patch was the first that
> > I noticed.
>
> Yeah. The above obviously *should* be the same as
>
> return inode;
>
> apart from a few casts. But if the casts matter, there's something else
> wrong.
befs_lookup, which the above gem is from, returns a dentry *.
And given either
return (dentry *)inode;
or
return ERR_PTR(PTR_ERR(inode));
I tend to prefer the latter.
On Mon, 1 Oct 2007, Christoph Hellwig wrote:
>
> befs_lookup, which the above gem is from, returns a dentry *.
Ahh, ok. Then it actually makes sense. Although I'd prefer it if people
planned on writing code like that more along the lines of
error = PTR_ERR(inode);
if (IS_ERR(inode)
return ERR_PTR(error);
because let's face it, the compiler can turn this into nice code, and
humans can read it much better even if it's got an "unnecessary" extra
variable etc..
Linus
> return ERR_PTR(PTR_ERR(inode));
>
> I tend to prefer the latter.
It seems like a pretty noisy way to get a (void *) cast :/. Maybe a
function that has the cast but makes sure it's only used for IS_ERR()
pointers?
/* haha, continuing the fine tradition of terrible names in this
api.. */
static inline void *PTR_PTR(void *err_ptr) {
BUG_ON(!IS_ERR(err_ptr) || !err_ptr);
return err_ptr;
}
Meh.
- z
On Mon, 2007-10-01 at 14:11 +0100, David Howells wrote:
> 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(-)
--
David Kleikamp
IBM Linux Technology Center
> diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
> index 0079b2c..d8fb795 100644
> --- a/fs/ext2/inode.c
> +++ b/fs/ext2/inode.c
...
> +
> + raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);
> if (IS_ERR(raw_inode))
> goto bad_inode;
Hmm, why don't you use the return value from raw_inode? It can be
either -EIO or -EINVAL if 'ino' was invalid...
Otherwise the patch looks fine.
Honza
--
Jan Kara <[email protected]>
SuSE CR Labs
> diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
> index e45dbd6..c2f0a0d 100644
> --- a/fs/ext3/ialloc.c
> +++ b/fs/ext3/ialloc.c
> @@ -646,7 +646,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
> unsigned long block_group;
> int bit;
> struct buffer_head *bitmap_bh = NULL;
> - struct inode *inode = NULL;
> + struct inode *inode = ERR_PTR(-EIO);
>
> /* Error cases - e2fsck has already cleaned up for us */
> if (ino > max_ino) {
> @@ -668,9 +668,14 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
> * 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) {
> + if (ext3_test_bit(bit, bitmap_bh->b_data))
> + goto out;
> +
> + inode = ext3_iget(sb, ino);
> + if (IS_ERR(inode))
> + goto out;
> +
> + if (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",
But if you 'goto out' in some branches, we loose the ext3_warning()
which we probably don't want.
> diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
> index c1fa190..78bfab5 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);
Wouldn't here -EIO be more appropriate?
> @@ -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);
And similarly here...
> @@ -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,25 @@ 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);
> + if (PTR_ERR(root) == -ENOMEM)
> + ret = -ENOMEM;
Why don't we use PTR_ERR() always? Is there some reason not to return
-EIO?
Honza
--
Jan Kara <[email protected]>
SuSE CR Labs
And one more thing...
> diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
> index e45dbd6..c2f0a0d 100644
> --- a/fs/ext3/ialloc.c
> +++ b/fs/ext3/ialloc.c
> @@ -646,7 +646,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
> unsigned long block_group;
> int bit;
> struct buffer_head *bitmap_bh = NULL;
> - struct inode *inode = NULL;
> + struct inode *inode = ERR_PTR(-EIO);
>
> /* Error cases - e2fsck has already cleaned up for us */
> if (ino > max_ino) {
> @@ -668,9 +668,14 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
> * 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) {
> + if (ext3_test_bit(bit, bitmap_bh->b_data))
> + goto out;
You inverted the test here, didn't you?
Honza
--
Jan Kara <[email protected]>
SuSE CR Labs
> diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
> index 427f830..8bb63f2 100644
> --- a/fs/ext4/ialloc.c
> +++ b/fs/ext4/ialloc.c
> @@ -682,9 +682,14 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
> * 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) {
> + if (ext4_test_bit(bit, bitmap_bh->b_data))
> + goto out;
> +
> + inode = ext4_iget(sb, ino);
> + if (IS_ERR(inode))
> + goto out;
> +
> + if (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",
Same comments as for ext3 - I think you reversed ext4_test_bit() test
and also the warning won't be issued in some cases which is wrong.
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index 5fdb862..af98d07 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);
-EIO more appropriate here?
Honza
--
Jan Kara <[email protected]>
SuSE CR Labs
Zach Brown <[email protected]> wrote:
> /* haha, continuing the fine tradition of terrible names in this api.. */
> static inline void *PTR_PTR(void *err_ptr) {
> BUG_ON(!IS_ERR(err_ptr) || !err_ptr);
> return err_ptr;
> }
How about ERR_CAST() instead? Or maybe CAST_ERR()?
struct dentry *blah(...)
{
struct inode *inode;
inode = thing(...);
if (IS_ERR(inode))
return ERR_CAST(inode);
}
Where ERR_CAST is defined as:
static inline void *ERR_CAST(const void *error)
{
return (void *) x;
}
David
Jan Kara <[email protected]> wrote:
> Hmm, why don't you use the return value from raw_inode? It can be
> either -EIO or -EINVAL if 'ino' was invalid...
Good point. Altered.
David
On Tue, 2007-10-02 at 13:32 +0100, David Howells wrote:
> Zach Brown <[email protected]> wrote:
>
> > /* haha, continuing the fine tradition of terrible names in this api.. */
> > static inline void *PTR_PTR(void *err_ptr) {
> > BUG_ON(!IS_ERR(err_ptr) || !err_ptr);
> > return err_ptr;
> > }
>
> How about ERR_CAST() instead? Or maybe CAST_ERR()?
It's a better name than PTR_PTR(). :-)
>
> struct dentry *blah(...)
> {
> struct inode *inode;
>
> inode = thing(...);
> if (IS_ERR(inode))
> return ERR_CAST(inode);
> }
>
> Where ERR_CAST is defined as:
>
> static inline void *ERR_CAST(const void *error)
> {
> return (void *) x;
> }
Of course, the cast is unnecessary, and I'm sure you meant to return
error:
static inline void *ERR_CAST(const void *error)
{
return error;
}
Shaggy
--
David Kleikamp
IBM Linux Technology Center
Jan Kara <[email protected]> wrote:
> But if you 'goto out' in some branches, we loose the ext3_warning()
> which we probably don't want.
Ugh. Okay, I need to rework the changes to that function.
> > return ERR_PTR(-EACCES);
> Wouldn't here -EIO be more appropriate?
I would have thought so, but -EACCES was what it returned before I touched it.
OTOH, it's calling ext3_error(), so EIO ought to be the right thing to do.
I'll alter it and see if anyone complains.
> Why don't we use PTR_ERR() always? Is there some reason not to return
> -EIO?
I do wonder why it used to return EINVAL rather than EIO. It's understandable
if the magic number doesn't match, but if it appears to be an otherwise
corrupt filesystem, then yes, I guess it should return EIO. I'll change it.
David
Dave Kleikamp <[email protected]> wrote:
> Of course, the cast is unnecessary,
The cast is necessary as the argument is a const pointer and the return type
is not.
> and I'm sure you meant to return error:
Oops. Yes, I changed my mind and renamed the argument to be 'error', but
forgot to change the reference to it.
David
Jan Kara <[email protected]> wrote:
> Same comments as for ext3 - I think you reversed ext4_test_bit() test
> and also the warning won't be issued in some cases which is wrong.
Same replies as for ext3 too. Blech.
You should find altered patches landing in your inbox if you'd care to inspect
them.
Thanks,
David
On Tue, 2007-10-02 at 14:24 +0100, David Howells wrote:
> Dave Kleikamp <[email protected]> wrote:
>
> > Of course, the cast is unnecessary,
>
> The cast is necessary as the argument is a const pointer and the return type
> is not.
Ah yes. I stand corrected.
--
David Kleikamp
IBM Linux Technology Center