Commit e82c3147 authored by Al Viro's avatar Al Viro

hpfs: handle allocation failures in hpfs_add_pos()

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 1d1bb236
...@@ -44,7 +44,11 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence) ...@@ -44,7 +44,11 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
else goto fail; else goto fail;
if (pos == 12) 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: ok:
filp->f_pos = new_off; filp->f_pos = new_off;
hpfs_unlock(s); hpfs_unlock(s);
...@@ -141,8 +145,10 @@ static int hpfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -141,8 +145,10 @@ static int hpfs_readdir(struct file *file, struct dir_context *ctx)
ctx->pos = 1; ctx->pos = 1;
} }
if (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; 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; file->f_version = inode->i_version;
} }
next_pos = ctx->pos; next_pos = ctx->pos;
......
...@@ -21,7 +21,7 @@ static loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde) ...@@ -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; 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); struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
int i = 0; int i = 0;
...@@ -29,11 +29,12 @@ void hpfs_add_pos(struct inode *inode, loff_t *pos) ...@@ -29,11 +29,12 @@ void hpfs_add_pos(struct inode *inode, loff_t *pos)
if (hpfs_inode->i_rddir_off) if (hpfs_inode->i_rddir_off)
for (; hpfs_inode->i_rddir_off[i]; i++) 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 (!(i&0x0f)) {
if (!(ppos = kmalloc((i+0x11) * sizeof(loff_t*), GFP_NOFS))) { if (!(ppos = kmalloc((i+0x11) * sizeof(loff_t*), GFP_NOFS))) {
pr_err("out of memory for position list\n"); pr_err("out of memory for position list\n");
return; return -ENOMEM;
} }
if (hpfs_inode->i_rddir_off) { if (hpfs_inode->i_rddir_off) {
memcpy(ppos, hpfs_inode->i_rddir_off, i * sizeof(loff_t)); 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) ...@@ -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] = pos;
hpfs_inode->i_rddir_off[i + 1] = NULL; hpfs_inode->i_rddir_off[i + 1] = NULL;
return 0;
} }
void hpfs_del_pos(struct inode *inode, loff_t *pos) void hpfs_del_pos(struct inode *inode, loff_t *pos)
......
...@@ -242,7 +242,7 @@ extern const struct file_operations hpfs_dir_ops; ...@@ -242,7 +242,7 @@ extern const struct file_operations hpfs_dir_ops;
/* dnode.c */ /* 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 *); void hpfs_del_pos(struct inode *, loff_t *);
struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *, struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *,
const unsigned char *, unsigned, secno); const unsigned char *, unsigned, secno);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment