Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull UDF fixes and cleanups from Jan Kara:
 "The contains some small fixes and improvements in error handling for
  UDF.

  Bundled is also one ext3 coding style fix and a fix in quota
  documentation"

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  udf: fix udf_load_pvoldesc()
  udf: remove double err declaration in udf_file_write_iter()
  UDF: support NFSv2 export
  fs: ext3: super: fixed a space coding style issue
  quota: Update documentation
  udf: Return error from udf_find_entry()
  udf: Make udf_get_filename() return error instead of 0 length file name
  udf: bug on exotic flag in udf_get_filename()
  udf: improve error management in udf_CS0toNLS()
  udf: improve error management in udf_CS0toUTF8()
  udf: unicode: update function name in comments
  udf: remove unnecessary test in udf_build_ustr_exact()
  udf: Return -ENOMEM when allocation fails in udf_get_filename()
This commit is contained in:
Linus Torvalds 2015-06-24 20:07:10 -07:00
commit a7296b49fb
8 changed files with 124 additions and 60 deletions

View file

@ -32,7 +32,10 @@ The interface uses generic netlink framework (see
http://lwn.net/Articles/208755/ and http://people.suug.ch/~tgr/libnl/ for more http://lwn.net/Articles/208755/ and http://people.suug.ch/~tgr/libnl/ for more
details about this layer). The name of the quota generic netlink interface details about this layer). The name of the quota generic netlink interface
is "VFS_DQUOT". Definitions of constants below are in <linux/quota.h>. is "VFS_DQUOT". Definitions of constants below are in <linux/quota.h>.
Currently, the interface supports only one message type QUOTA_NL_C_WARNING. Since the quota netlink protocol is not namespace aware, quota netlink messages
are sent only in initial network namespace.
Currently, the interface supports only one message type QUOTA_NL_C_WARNING.
This command is used to send a notification about any of the above mentioned This command is used to send a notification about any of the above mentioned
events. Each message has six attributes. These are (type of the argument is events. Each message has six attributes. These are (type of the argument is
in parentheses): in parentheses):

View file

@ -1908,7 +1908,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
sbi->s_mount_state = le16_to_cpu(es->s_state); sbi->s_mount_state = le16_to_cpu(es->s_state);
sbi->s_addr_per_block_bits = ilog2(EXT3_ADDR_PER_BLOCK(sb)); sbi->s_addr_per_block_bits = ilog2(EXT3_ADDR_PER_BLOCK(sb));
sbi->s_desc_per_block_bits = ilog2(EXT3_DESC_PER_BLOCK(sb)); sbi->s_desc_per_block_bits = ilog2(EXT3_DESC_PER_BLOCK(sb));
for (i=0; i < 4; i++) for (i = 0; i < 4; i++)
sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
sbi->s_def_hash_version = es->s_def_hash_version; sbi->s_def_hash_version = es->s_def_hash_version;
i = le32_to_cpu(es->s_flags); i = le32_to_cpu(es->s_flags);

View file

@ -168,7 +168,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
} }
flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN); flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN);
if (!flen) if (flen < 0)
continue; continue;
tloc = lelb_to_cpu(cfi.icb.extLocation); tloc = lelb_to_cpu(cfi.icb.extLocation);

View file

@ -152,8 +152,6 @@ static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (retval > 0) { if (retval > 0) {
ssize_t err;
mark_inode_dirty(inode); mark_inode_dirty(inode);
err = generic_write_sync(file, iocb->ki_pos - retval, retval); err = generic_write_sync(file, iocb->ki_pos - retval, retval);
if (err < 0) if (err < 0)

View file

@ -138,6 +138,25 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
return 0; return 0;
} }
/**
* udf_find_entry - find entry in given directory.
*
* @dir: directory inode to search in
* @child: qstr of the name
* @fibh: buffer head / inode with file identifier descriptor we found
* @cfi: found file identifier descriptor with given name
*
* This function searches in the directory @dir for a file name @child. When
* found, @fibh points to the buffer head(s) (bh is NULL for in ICB
* directories) containing the file identifier descriptor (FID). In that case
* the function returns pointer to the FID in the buffer or inode - but note
* that FID may be split among two buffers (blocks) so accessing it via that
* pointer isn't easily possible. This pointer can be used only as an iterator
* for other directory manipulation functions. For inspection of the FID @cfi
* can be used - the found FID is copied there.
*
* Returns pointer to FID, NULL when nothing found, or error code.
*/
static struct fileIdentDesc *udf_find_entry(struct inode *dir, static struct fileIdentDesc *udf_find_entry(struct inode *dir,
const struct qstr *child, const struct qstr *child,
struct udf_fileident_bh *fibh, struct udf_fileident_bh *fibh,
@ -167,8 +186,11 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
fibh->soffset = fibh->eoffset = f_pos & (sb->s_blocksize - 1); fibh->soffset = fibh->eoffset = f_pos & (sb->s_blocksize - 1);
if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
if (inode_bmap(dir, f_pos >> sb->s_blocksize_bits, &epos, if (inode_bmap(dir, f_pos >> sb->s_blocksize_bits, &epos,
&eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) {
fi = ERR_PTR(-EIO);
goto out_err; goto out_err;
}
block = udf_get_lb_pblock(sb, &eloc, offset); block = udf_get_lb_pblock(sb, &eloc, offset);
if ((++offset << sb->s_blocksize_bits) < elen) { if ((++offset << sb->s_blocksize_bits) < elen) {
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
@ -179,19 +201,25 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
offset = 0; offset = 0;
fibh->sbh = fibh->ebh = udf_tread(sb, block); fibh->sbh = fibh->ebh = udf_tread(sb, block);
if (!fibh->sbh) if (!fibh->sbh) {
fi = ERR_PTR(-EIO);
goto out_err; goto out_err;
}
} }
fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
if (!fname) if (!fname) {
fi = ERR_PTR(-ENOMEM);
goto out_err; goto out_err;
}
while (f_pos < size) { while (f_pos < size) {
fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
&elen, &offset); &elen, &offset);
if (!fi) if (!fi) {
fi = ERR_PTR(-EIO);
goto out_err; goto out_err;
}
liu = le16_to_cpu(cfi->lengthOfImpUse); liu = le16_to_cpu(cfi->lengthOfImpUse);
lfi = cfi->lengthFileIdent; lfi = cfi->lengthFileIdent;
@ -234,12 +262,17 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
continue; continue;
flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN); flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN);
if (flen && udf_match(flen, fname, child->len, child->name)) if (flen < 0) {
fi = ERR_PTR(flen);
goto out_err;
}
if (udf_match(flen, fname, child->len, child->name))
goto out_ok; goto out_ok;
} }
out_err:
fi = NULL; fi = NULL;
out_err:
if (fibh->sbh != fibh->ebh) if (fibh->sbh != fibh->ebh)
brelse(fibh->ebh); brelse(fibh->ebh);
brelse(fibh->sbh); brelse(fibh->sbh);
@ -256,6 +289,7 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
struct inode *inode = NULL; struct inode *inode = NULL;
struct fileIdentDesc cfi; struct fileIdentDesc cfi;
struct udf_fileident_bh fibh; struct udf_fileident_bh fibh;
struct fileIdentDesc *fi;
if (dentry->d_name.len > UDF_NAME_LEN - 2) if (dentry->d_name.len > UDF_NAME_LEN - 2)
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
@ -275,7 +309,11 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
} else } else
#endif /* UDF_RECOVERY */ #endif /* UDF_RECOVERY */
if (udf_find_entry(dir, &dentry->d_name, &fibh, &cfi)) { fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
if (IS_ERR(fi))
return ERR_CAST(fi);
if (fi) {
struct kernel_lb_addr loc; struct kernel_lb_addr loc;
if (fibh.sbh != fibh.ebh) if (fibh.sbh != fibh.ebh)
@ -774,8 +812,11 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
retval = -ENOENT; retval = -ENOENT;
fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi); fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
if (!fi) if (IS_ERR_OR_NULL(fi)) {
if (fi)
retval = PTR_ERR(fi);
goto out; goto out;
}
retval = -EIO; retval = -EIO;
tloc = lelb_to_cpu(cfi.icb.extLocation); tloc = lelb_to_cpu(cfi.icb.extLocation);
@ -817,8 +858,12 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)
retval = -ENOENT; retval = -ENOENT;
fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi); fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
if (!fi)
if (IS_ERR_OR_NULL(fi)) {
if (fi)
retval = PTR_ERR(fi);
goto out; goto out;
}
retval = -EIO; retval = -EIO;
tloc = lelb_to_cpu(cfi.icb.extLocation); tloc = lelb_to_cpu(cfi.icb.extLocation);
@ -1049,24 +1094,30 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
struct udf_inode_info *old_iinfo = UDF_I(old_inode); struct udf_inode_info *old_iinfo = UDF_I(old_inode);
ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi); ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
if (ofi) { if (IS_ERR(ofi)) {
if (ofibh.sbh != ofibh.ebh) retval = PTR_ERR(ofi);
brelse(ofibh.ebh); goto end_rename;
brelse(ofibh.sbh);
} }
if (ofibh.sbh != ofibh.ebh)
brelse(ofibh.ebh);
brelse(ofibh.sbh);
tloc = lelb_to_cpu(ocfi.icb.extLocation); tloc = lelb_to_cpu(ocfi.icb.extLocation);
if (!ofi || udf_get_lb_pblock(old_dir->i_sb, &tloc, 0) if (!ofi || udf_get_lb_pblock(old_dir->i_sb, &tloc, 0)
!= old_inode->i_ino) != old_inode->i_ino)
goto end_rename; goto end_rename;
nfi = udf_find_entry(new_dir, &new_dentry->d_name, &nfibh, &ncfi); nfi = udf_find_entry(new_dir, &new_dentry->d_name, &nfibh, &ncfi);
if (nfi) { if (IS_ERR(nfi)) {
if (!new_inode) { retval = PTR_ERR(nfi);
if (nfibh.sbh != nfibh.ebh) goto end_rename;
brelse(nfibh.ebh); }
brelse(nfibh.sbh); if (nfi && !new_inode) {
nfi = NULL; if (nfibh.sbh != nfibh.ebh)
} brelse(nfibh.ebh);
brelse(nfibh.sbh);
nfi = NULL;
} }
if (S_ISDIR(old_inode->i_mode)) { if (S_ISDIR(old_inode->i_mode)) {
int offset = udf_ext0_offset(old_inode); int offset = udf_ext0_offset(old_inode);
@ -1221,7 +1272,7 @@ static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
static struct dentry *udf_fh_to_dentry(struct super_block *sb, static struct dentry *udf_fh_to_dentry(struct super_block *sb,
struct fid *fid, int fh_len, int fh_type) struct fid *fid, int fh_len, int fh_type)
{ {
if ((fh_len != 3 && fh_len != 5) || if (fh_len < 3 ||
(fh_type != FILEID_UDF_WITH_PARENT && (fh_type != FILEID_UDF_WITH_PARENT &&
fh_type != FILEID_UDF_WITHOUT_PARENT)) fh_type != FILEID_UDF_WITHOUT_PARENT))
return NULL; return NULL;
@ -1233,7 +1284,7 @@ static struct dentry *udf_fh_to_dentry(struct super_block *sb,
static struct dentry *udf_fh_to_parent(struct super_block *sb, static struct dentry *udf_fh_to_parent(struct super_block *sb,
struct fid *fid, int fh_len, int fh_type) struct fid *fid, int fh_len, int fh_type)
{ {
if (fh_len != 5 || fh_type != FILEID_UDF_WITH_PARENT) if (fh_len < 5 || fh_type != FILEID_UDF_WITH_PARENT)
return NULL; return NULL;
return udf_nfs_get_inode(sb, fid->udf.parent_block, return udf_nfs_get_inode(sb, fid->udf.parent_block,

View file

@ -927,17 +927,23 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
#endif #endif
} }
if (!udf_build_ustr(instr, pvoldesc->volIdent, 32)) if (!udf_build_ustr(instr, pvoldesc->volIdent, 32)) {
if (udf_CS0toUTF8(outstr, instr)) { ret = udf_CS0toUTF8(outstr, instr);
strncpy(UDF_SB(sb)->s_volume_ident, outstr->u_name, if (ret < 0)
outstr->u_len > 31 ? 31 : outstr->u_len); goto out_bh;
udf_debug("volIdent[] = '%s'\n",
UDF_SB(sb)->s_volume_ident);
}
if (!udf_build_ustr(instr, pvoldesc->volSetIdent, 128)) strncpy(UDF_SB(sb)->s_volume_ident, outstr->u_name,
if (udf_CS0toUTF8(outstr, instr)) outstr->u_len > 31 ? 31 : outstr->u_len);
udf_debug("volSetIdent[] = '%s'\n", outstr->u_name); udf_debug("volIdent[] = '%s'\n", UDF_SB(sb)->s_volume_ident);
}
if (!udf_build_ustr(instr, pvoldesc->volSetIdent, 128)) {
ret = udf_CS0toUTF8(outstr, instr);
if (ret < 0)
goto out_bh;
udf_debug("volSetIdent[] = '%s'\n", outstr->u_name);
}
ret = 0; ret = 0;
out_bh: out_bh:

View file

@ -82,6 +82,9 @@ static int udf_pc_to_char(struct super_block *sb, unsigned char *from,
comp_len = udf_get_filename(sb, pc->componentIdent, comp_len = udf_get_filename(sb, pc->componentIdent,
pc->lengthComponentIdent, pc->lengthComponentIdent,
p, tolen); p, tolen);
if (comp_len < 0)
return comp_len;
p += comp_len; p += comp_len;
tolen -= comp_len; tolen -= comp_len;
if (tolen == 0) if (tolen == 0)

View file

@ -68,21 +68,16 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
/* /*
* udf_build_ustr_exact * udf_build_ustr_exact
*/ */
static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) static void udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
{ {
if ((!dest) || (!ptr) || (!exactsize))
return -1;
memset(dest, 0, sizeof(struct ustr)); memset(dest, 0, sizeof(struct ustr));
dest->u_cmpID = ptr[0]; dest->u_cmpID = ptr[0];
dest->u_len = exactsize - 1; dest->u_len = exactsize - 1;
memcpy(dest->u_name, ptr + 1, exactsize - 1); memcpy(dest->u_name, ptr + 1, exactsize - 1);
return 0;
} }
/* /*
* udf_ocu_to_utf8 * udf_CS0toUTF8
* *
* PURPOSE * PURPOSE
* Convert OSTA Compressed Unicode to the UTF-8 equivalent. * Convert OSTA Compressed Unicode to the UTF-8 equivalent.
@ -94,7 +89,7 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
* both of type "struct ustr *" * both of type "struct ustr *"
* *
* POST-CONDITIONS * POST-CONDITIONS
* <return> Zero on success. * <return> >= 0 on success.
* *
* HISTORY * HISTORY
* November 12, 1997 - Andrew E. Mileski * November 12, 1997 - Andrew E. Mileski
@ -117,7 +112,7 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
memset(utf_o, 0, sizeof(struct ustr)); memset(utf_o, 0, sizeof(struct ustr));
pr_err("unknown compression code (%d) stri=%s\n", pr_err("unknown compression code (%d) stri=%s\n",
cmp_id, ocu_i->u_name); cmp_id, ocu_i->u_name);
return 0; return -EINVAL;
} }
ocu = ocu_i->u_name; ocu = ocu_i->u_name;
@ -154,7 +149,7 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
/* /*
* *
* udf_utf8_to_ocu * udf_UTF8toCS0
* *
* PURPOSE * PURPOSE
* Convert UTF-8 to the OSTA Compressed Unicode equivalent. * Convert UTF-8 to the OSTA Compressed Unicode equivalent.
@ -270,7 +265,7 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
memset(utf_o, 0, sizeof(struct ustr)); memset(utf_o, 0, sizeof(struct ustr));
pr_err("unknown compression code (%d) stri=%s\n", pr_err("unknown compression code (%d) stri=%s\n",
cmp_id, ocu_i->u_name); cmp_id, ocu_i->u_name);
return 0; return -EINVAL;
} }
ocu = ocu_i->u_name; ocu = ocu_i->u_name;
@ -338,43 +333,51 @@ int udf_get_filename(struct super_block *sb, uint8_t *sname, int slen,
uint8_t *dname, int dlen) uint8_t *dname, int dlen)
{ {
struct ustr *filename, *unifilename; struct ustr *filename, *unifilename;
int len = 0; int ret;
if (!slen)
return -EIO;
filename = kmalloc(sizeof(struct ustr), GFP_NOFS); filename = kmalloc(sizeof(struct ustr), GFP_NOFS);
if (!filename) if (!filename)
return 0; return -ENOMEM;
unifilename = kmalloc(sizeof(struct ustr), GFP_NOFS); unifilename = kmalloc(sizeof(struct ustr), GFP_NOFS);
if (!unifilename) if (!unifilename) {
ret = -ENOMEM;
goto out1; goto out1;
}
if (udf_build_ustr_exact(unifilename, sname, slen)) udf_build_ustr_exact(unifilename, sname, slen);
goto out2;
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
if (!udf_CS0toUTF8(filename, unifilename)) { ret = udf_CS0toUTF8(filename, unifilename);
if (ret < 0) {
udf_debug("Failed in udf_get_filename: sname = %s\n", udf_debug("Failed in udf_get_filename: sname = %s\n",
sname); sname);
goto out2; goto out2;
} }
} else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, filename, ret = udf_CS0toNLS(UDF_SB(sb)->s_nls_map, filename,
unifilename)) { unifilename);
if (ret < 0) {
udf_debug("Failed in udf_get_filename: sname = %s\n", udf_debug("Failed in udf_get_filename: sname = %s\n",
sname); sname);
goto out2; goto out2;
} }
} else } else
goto out2; BUG();
len = udf_translate_to_linux(dname, dlen, ret = udf_translate_to_linux(dname, dlen,
filename->u_name, filename->u_len, filename->u_name, filename->u_len,
unifilename->u_name, unifilename->u_len); unifilename->u_name, unifilename->u_len);
/* Zero length filename isn't valid... */
if (ret == 0)
ret = -EINVAL;
out2: out2:
kfree(unifilename); kfree(unifilename);
out1: out1:
kfree(filename); kfree(filename);
return len; return ret;
} }
int udf_put_filename(struct super_block *sb, const uint8_t *sname, int udf_put_filename(struct super_block *sb, const uint8_t *sname,