hpfs: handle allocation failures in hpfs_add_pos()
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 12 May 2016 23:35:57 +0000 (19:35 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 12 May 2016 23:35:57 +0000 (19:35 -0400)
pr_err() is nice, but we'd better propagate the error
to caller and not proceed to violate the invariants
(namely, "every file with f_pos tied to directory block
should have its address visible in per-inode array").

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/hpfs/dir.c
fs/hpfs/dnode.c
fs/hpfs/hpfs_fn.h

index e57a53c..77b92ff 100644 (file)
@@ -44,7 +44,11 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
                else goto fail;
                if (pos == 12) goto fail;
        }
-       hpfs_add_pos(i, &filp->f_pos);
+       if (unlikely(hpfs_add_pos(i, &filp->f_pos) < 0)) {
+               hpfs_unlock(s);
+               inode_unlock(i);
+               return -ENOMEM;
+       }
 ok:
        filp->f_pos = new_off;
        hpfs_unlock(s);
@@ -141,8 +145,10 @@ static int hpfs_readdir(struct file *file, struct dir_context *ctx)
                        ctx->pos = 1;
                }
                if (ctx->pos == 1) {
+                       ret = hpfs_add_pos(inode, &file->f_pos);
+                       if (unlikely(ret < 0))
+                               goto out;
                        ctx->pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1;
-                       hpfs_add_pos(inode, &file->f_pos);
                        file->f_version = inode->i_version;
                }
                next_pos = ctx->pos;
index 2923a7b..86ab7e7 100644 (file)
@@ -21,7 +21,7 @@ static loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde)
        return ((loff_t)le32_to_cpu(d->self) << 4) | (loff_t)1;
 }
 
-void hpfs_add_pos(struct inode *inode, loff_t *pos)
+int hpfs_add_pos(struct inode *inode, loff_t *pos)
 {
        struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
        int i = 0;
@@ -29,11 +29,12 @@ void hpfs_add_pos(struct inode *inode, loff_t *pos)
 
        if (hpfs_inode->i_rddir_off)
                for (; hpfs_inode->i_rddir_off[i]; i++)
-                       if (hpfs_inode->i_rddir_off[i] == pos) return;
+                       if (hpfs_inode->i_rddir_off[i] == pos)
+                               return 0;
        if (!(i&0x0f)) {
                if (!(ppos = kmalloc((i+0x11) * sizeof(loff_t*), GFP_NOFS))) {
                        pr_err("out of memory for position list\n");
-                       return;
+                       return -ENOMEM;
                }
                if (hpfs_inode->i_rddir_off) {
                        memcpy(ppos, hpfs_inode->i_rddir_off, i * sizeof(loff_t));
@@ -43,6 +44,7 @@ void hpfs_add_pos(struct inode *inode, loff_t *pos)
        }
        hpfs_inode->i_rddir_off[i] = pos;
        hpfs_inode->i_rddir_off[i + 1] = NULL;
+       return 0;
 }
 
 void hpfs_del_pos(struct inode *inode, loff_t *pos)
index 975654a..aebb78f 100644 (file)
@@ -242,7 +242,7 @@ extern const struct file_operations hpfs_dir_ops;
 
 /* dnode.c */
 
-void hpfs_add_pos(struct inode *, loff_t *);
+int hpfs_add_pos(struct inode *, loff_t *);
 void hpfs_del_pos(struct inode *, loff_t *);
 struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *,
                                const unsigned char *, unsigned, secno);