[PATCH v3 4/9] ntfs: return errors from ntfs_attr_readall
Hyunchul Lee <[email protected]>
| Newsgroups | dev.linux.lists.ntfs |
|---|---|
| Message-ID | <[email protected]> |
ntfs_attr_readall() currently loses the failure reason for attribute lookup, allocation, and read failures by returning NULL. Return ERR_PTR() with the original error instead. The reparse parser can then propagate allocation and I/O errors without treating them as filesystem corruption. Signed-off-by: Hyunchul Lee <[email protected]> --- fs/ntfs/attrib.c | 8 +++++++- fs/ntfs/ea.c | 38 +++++++++++++++++++++++++++++++------- fs/ntfs/index.c | 4 ++-- fs/ntfs/reparse.c | 4 ++++ 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 990c3937a551..d9e844c481d8 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -5296,6 +5296,7 @@ int ntfs_attr_remove(struct ntfs_inode *ni, const __le32 type, __le16 *name, * On success a buffer is allocated with the content of the attribute * and which needs to be freed when it's not needed anymore. If the * @data_size parameter is non-NULL then the data size is set there. + * On error, an ERR_PTR() containing the negative error code is returned. */ void *ntfs_attr_readall(struct ntfs_inode *ni, const __le32 type, __le16 *name, u32 name_len, s64 *data_size) @@ -5310,6 +5311,7 @@ void *ntfs_attr_readall(struct ntfs_inode *ni, const __le32 type, bmp_vi = ntfs_attr_iget(VFS_I(ni), type, name, name_len); if (IS_ERR(bmp_vi)) { + ret = ERR_PTR(PTR_ERR(bmp_vi)); ntfs_debug("ntfs_attr_iget failed"); goto err_exit; } @@ -5319,17 +5321,21 @@ void *ntfs_attr_readall(struct ntfs_inode *ni, const __le32 type, (bmp_ni->type != AT_BITMAP || bmp_ni->data_size > ((ni->vol->nr_clusters + 7) >> 3))) { ntfs_error(sb, "Invalid attribute data size"); + ret = ERR_PTR(-EIO); goto out; } data = kvmalloc(bmp_ni->data_size, GFP_NOFS); - if (!data) + if (!data) { + ret = ERR_PTR(-ENOMEM); goto out; + } size = ntfs_inode_attr_pread(VFS_I(bmp_ni), 0, bmp_ni->data_size, (u8 *)data); if (size != bmp_ni->data_size) { ntfs_error(sb, "ntfs_attr_pread failed"); + ret = size < 0 ? ERR_PTR((int)size) : ERR_PTR(-EIO); kvfree(data); goto out; } diff --git a/fs/ntfs/ea.c b/fs/ntfs/ea.c index fc6cec7ce130..c8a3d9f07dc4 100644 --- a/fs/ntfs/ea.c +++ b/fs/ntfs/ea.c @@ -122,17 +122,19 @@ static int ntfs_get_ea(struct inode *inode, const char *name, size_t name_len, p_ea_info = ntfs_attr_readall(ni, AT_EA_INFORMATION, NULL, 0, &ea_info_size); - if (!p_ea_info || ea_info_size != sizeof(struct ea_information)) { + if (IS_ERR(p_ea_info)) + return PTR_ERR(p_ea_info); + if (ea_info_size != sizeof(struct ea_information)) { kvfree(p_ea_info); - return -ENODATA; + return -EIO; } ea_info_qlen = le32_to_cpu(p_ea_info->ea_query_length); kvfree(p_ea_info); ea_buf = ntfs_attr_readall(ni, AT_EA, NULL, 0, &all_ea_size); - if (!ea_buf) - return -ENODATA; + if (IS_ERR(ea_buf)) + return PTR_ERR(ea_buf); if (ea_info_qlen > all_ea_size) { err = -EIO; @@ -208,10 +210,22 @@ static int ntfs_set_ea(struct inode *inode, const char *name, size_t name_len, if (ntfs_attr_exist(ni, AT_EA_INFORMATION, AT_UNNAMED, 0)) { p_ea_info = ntfs_attr_readall(ni, AT_EA_INFORMATION, NULL, 0, &ea_info_size); - if (!p_ea_info || ea_info_size != sizeof(struct ea_information)) + if (IS_ERR(p_ea_info)) { + err = PTR_ERR(p_ea_info); + p_ea_info = NULL; goto out; + } + if (ea_info_size != sizeof(struct ea_information)) { + err = -EIO; + goto out; + } ea_buf = ntfs_attr_readall(ni, AT_EA, NULL, 0, &all_ea_size); + if (IS_ERR(ea_buf)) { + err = PTR_ERR(ea_buf); + ea_buf = NULL; + goto out; + } if (!ea_buf) { ea_info_qsize = 0; kvfree(p_ea_info); @@ -514,14 +528,24 @@ ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size) mutex_lock(&NTFS_I(inode)->mrec_lock); ea_info = ntfs_attr_readall(ni, AT_EA_INFORMATION, NULL, 0, &ea_info_size); - if (!ea_info || ea_info_size != sizeof(struct ea_information)) + if (IS_ERR(ea_info)) { + err = PTR_ERR(ea_info); + ea_info = NULL; goto out; + } + if (ea_info_size != sizeof(struct ea_information)) { + err = -EIO; + goto out; + } ea_info_qsize = le32_to_cpu(ea_info->ea_query_length); ea_buf = ntfs_attr_readall(ni, AT_EA, NULL, 0, &ea_buf_size); - if (!ea_buf) + if (IS_ERR(ea_buf)) { + err = PTR_ERR(ea_buf); + ea_buf = NULL; goto out; + } if (ea_info_qsize > ea_buf_size || ea_info_qsize == 0) goto out; diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index 8c8eb13859ab..46a8b19c0723 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -1108,8 +1108,8 @@ static s64 ntfs_ibm_get_free(struct ntfs_index_context *icx) bm = ntfs_attr_readall(icx->idx_ni, AT_BITMAP, icx->name, icx->name_len, &size); - if (!bm) - return -EIO; + if (IS_ERR(bm)) + return PTR_ERR(bm); for (byte = 0; byte < size; byte++) { if (bm[byte] == 255) diff --git a/fs/ntfs/reparse.c b/fs/ntfs/reparse.c index 0d3988992119..b8d601f5500f 100644 --- a/fs/ntfs/reparse.c +++ b/fs/ntfs/reparse.c @@ -256,6 +256,8 @@ unsigned int ntfs_make_symlink(struct ntfs_inode *ni) reparse_attr = ntfs_attr_readall(ni, AT_REPARSE_POINT, NULL, 0, &attr_size); + if (IS_ERR(reparse_attr)) + reparse_attr = NULL; if (reparse_attr && valid_reparse_data(ni, reparse_attr, attr_size)) { err = -EINVAL; @@ -335,6 +337,8 @@ unsigned int ntfs_reparse_tag_dt_types(struct ntfs_volume *vol, unsigned long mr reparse_attr = (struct reparse_point *)ntfs_attr_readall(NTFS_I(vi), AT_REPARSE_POINT, NULL, 0, &attr_size); + if (IS_ERR(reparse_attr)) + reparse_attr = NULL; if (reparse_attr && attr_size >= sizeof(*reparse_attr)) { switch (reparse_attr->reparse_tag) { -- 2.43.0