mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
Changes for 6.12-rc3
New: implement fallocate for compressed files; add support for the compression attribute; optimize large writes to sparse files. Fixed: fix several potential deadlock scenarios; fix various internal bugs detected by syzbot; add checks before accessing NTFS structures during parsing; correct the format of output messages. Refactored: replace fsparam_flag_no with fsparam_flag in options parser; remove unused functions and macros. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEh0DEKNP0I9IjwfWEqbAzH4MkB7YFAmcFRkgACgkQqbAzH4Mk B7aQdQ//VT6lzBaxSZ0dm3xs/ygQYE3ter1OczAMQxh70O5px+Z0li5WCXQQe31W I74MmAy2G7C+JdzMkSc4F7+pFF21DO+1WQjODl9rP7yoHiLteiLFkMI+P5tHuFFT VPupAiCDQgm6QCtW2wofp/WR0ooxpLzC/yQsILrhUXJHdEY21oHLy/MQSOhVnv2k VeFdWA70+YS+JEQ+YyZBSeGeMVMQG9VROA57dZ+eAy1vgBUJGcKhYp9v4eiWG1uT A8rnV81FiHu+49OrE+ZwStguHkxu30dvlHuOqKW0pLW9/XoKCFf9w0WqLOGrAxLs lKznVgQZ521+QW+lNURMHBZt/bqQxQQInuOOH7jwLyBh0tmKoZlIU9Vw4V3yrm3t 9NELb0FR/FeH02O89nMHl0SeaxDJvgFHDnfoOShuHaffur61d4RjChxqB4QcibOl Ibvtns71Uo89ngPIXdeTJK+7XZQVmAZHBXXYL+Rwr84Yv0tyn2q8DbrqzmphiYlR wbLyVBGqtx0ZcN/geuFLiVt2W/HSMPocXqrxv791ALX6cryL+CZdolQP7vWjt4Vh rKoaRZYN8fdcfT+BIYy95Kz0k12T7ColOoMfxVwugxK9ypF6tH6BJBwYXjCW4MOv AhkszJcsISxMKidsbzZA9xESM6M3sLHcW0swjAwWWRhc5zbSe6E= =j71V -----END PGP SIGNATURE----- Merge tag 'ntfs3_for_6.12' of https://github.com/Paragon-Software-Group/linux-ntfs3 Pull ntfs3 updates from Konstantin Komarov: "New: - implement fallocate for compressed files - add support for the compression attribute - optimize large writes to sparse files Fixes: - fix several potential deadlock scenarios - fix various internal bugs detected by syzbot - add checks before accessing NTFS structures during parsing - correct the format of output messages Refactoring: - replace fsparam_flag_no with fsparam_flag in options parser - remove unused functions and macros" * tag 'ntfs3_for_6.12' of https://github.com/Paragon-Software-Group/linux-ntfs3: (25 commits) fs/ntfs3: Format output messages like others fs in kernel fs/ntfs3: Additional check in ntfs_file_release fs/ntfs3: Fix general protection fault in run_is_mapped_full fs/ntfs3: Sequential field availability check in mi_enum_attr() fs/ntfs3: Additional check in ni_clear() fs/ntfs3: Fix possible deadlock in mi_read ntfs3: Change to non-blocking allocation in ntfs_d_hash fs/ntfs3: Remove unused al_delete_le fs/ntfs3: Rename ntfs3_setattr into ntfs_setattr fs/ntfs3: Replace fsparam_flag_no -> fsparam_flag fs/ntfs3: Add support for the compression attribute fs/ntfs3: Implement fallocate for compressed files fs/ntfs3: Make checks in run_unpack more clear fs/ntfs3: Add rough attr alloc_size check fs/ntfs3: Stale inode instead of bad fs/ntfs3: Refactor enum_rstbl to suppress static checker fs/ntfs3: Fix sparse warning in ni_fiemap fs/ntfs3: Fix warning possible deadlock in ntfs_set_state fs/ntfs3: Fix sparse warning for bigendian fs/ntfs3: Separete common code for file_read/write iter/splice ...
This commit is contained in:
commit
5b7c893ed5
@ -976,15 +976,17 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
|
||||
goto out;
|
||||
|
||||
/* Check for compressed frame. */
|
||||
err = attr_is_frame_compressed(ni, attr, vcn >> NTFS_LZNT_CUNIT, &hint);
|
||||
err = attr_is_frame_compressed(ni, attr_b, vcn >> NTFS_LZNT_CUNIT,
|
||||
&hint);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (hint) {
|
||||
/* if frame is compressed - don't touch it. */
|
||||
*lcn = COMPRESSED_LCN;
|
||||
*len = hint;
|
||||
err = -EOPNOTSUPP;
|
||||
/* length to the end of frame. */
|
||||
*len = NTFS_LZNT_CLUSTERS - (vcn & (NTFS_LZNT_CLUSTERS - 1));
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1027,16 +1029,16 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
|
||||
|
||||
/* Check if 'vcn' and 'vcn0' in different attribute segments. */
|
||||
if (vcn < svcn || evcn1 <= vcn) {
|
||||
/* Load attribute for truncated vcn. */
|
||||
attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0,
|
||||
&vcn, &mi);
|
||||
if (!attr) {
|
||||
struct ATTRIB *attr2;
|
||||
/* Load runs for truncated vcn. */
|
||||
attr2 = ni_find_attr(ni, attr_b, &le_b, ATTR_DATA, NULL,
|
||||
0, &vcn, &mi);
|
||||
if (!attr2) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
svcn = le64_to_cpu(attr->nres.svcn);
|
||||
evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
|
||||
err = attr_load_runs(attr, ni, run, NULL);
|
||||
evcn1 = le64_to_cpu(attr2->nres.evcn) + 1;
|
||||
err = attr_load_runs(attr2, ni, run, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
@ -1517,6 +1519,9 @@ out:
|
||||
|
||||
/*
|
||||
* attr_is_frame_compressed - Used to detect compressed frame.
|
||||
*
|
||||
* attr - base (primary) attribute segment.
|
||||
* Only base segments contains valid 'attr->nres.c_unit'
|
||||
*/
|
||||
int attr_is_frame_compressed(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
CLST frame, CLST *clst_data)
|
||||
@ -2600,3 +2605,74 @@ int attr_force_nonresident(struct ntfs_inode *ni)
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the compression of data attribute
|
||||
*/
|
||||
int attr_set_compress(struct ntfs_inode *ni, bool compr)
|
||||
{
|
||||
struct ATTRIB *attr;
|
||||
struct mft_inode *mi;
|
||||
|
||||
attr = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL, &mi);
|
||||
if (!attr)
|
||||
return -ENOENT;
|
||||
|
||||
if (is_attr_compressed(attr) == !!compr) {
|
||||
/* Already required compressed state. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (attr->non_res) {
|
||||
u16 run_off;
|
||||
u32 run_size;
|
||||
char *run;
|
||||
|
||||
if (attr->nres.data_size) {
|
||||
/*
|
||||
* There are rare cases when it possible to change
|
||||
* compress state without big changes.
|
||||
* TODO: Process these cases.
|
||||
*/
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
run_off = le16_to_cpu(attr->nres.run_off);
|
||||
run_size = le32_to_cpu(attr->size) - run_off;
|
||||
run = Add2Ptr(attr, run_off);
|
||||
|
||||
if (!compr) {
|
||||
/* remove field 'attr->nres.total_size'. */
|
||||
memmove(run - 8, run, run_size);
|
||||
run_off -= 8;
|
||||
}
|
||||
|
||||
if (!mi_resize_attr(mi, attr, compr ? +8 : -8)) {
|
||||
/*
|
||||
* Ignore rare case when there are no 8 bytes in record with attr.
|
||||
* TODO: split attribute.
|
||||
*/
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (compr) {
|
||||
/* Make a gap for 'attr->nres.total_size'. */
|
||||
memmove(run + 8, run, run_size);
|
||||
run_off += 8;
|
||||
attr->nres.total_size = attr->nres.alloc_size;
|
||||
}
|
||||
attr->nres.run_off = cpu_to_le16(run_off);
|
||||
}
|
||||
|
||||
/* Update data attribute flags. */
|
||||
if (compr) {
|
||||
attr->flags |= ATTR_FLAG_COMPRESSED;
|
||||
attr->nres.c_unit = NTFS_LZNT_CUNIT;
|
||||
} else {
|
||||
attr->flags &= ~ATTR_FLAG_COMPRESSED;
|
||||
attr->nres.c_unit = 0;
|
||||
}
|
||||
mi->dirty = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -382,59 +382,6 @@ bool al_remove_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* al_delete_le - Delete first le from the list which matches its parameters.
|
||||
*/
|
||||
bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn,
|
||||
const __le16 *name, u8 name_len, const struct MFT_REF *ref)
|
||||
{
|
||||
u16 size;
|
||||
struct ATTR_LIST_ENTRY *le;
|
||||
size_t off;
|
||||
typeof(ni->attr_list) *al = &ni->attr_list;
|
||||
|
||||
/* Scan forward to the first le that matches the input. */
|
||||
le = al_find_ex(ni, NULL, type, name, name_len, &vcn);
|
||||
if (!le)
|
||||
return false;
|
||||
|
||||
off = PtrOffset(al->le, le);
|
||||
|
||||
next:
|
||||
if (off >= al->size)
|
||||
return false;
|
||||
if (le->type != type)
|
||||
return false;
|
||||
if (le->name_len != name_len)
|
||||
return false;
|
||||
if (name_len && ntfs_cmp_names(le_name(le), name_len, name, name_len,
|
||||
ni->mi.sbi->upcase, true))
|
||||
return false;
|
||||
if (le64_to_cpu(le->vcn) != vcn)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* The caller specified a segment reference, so we have to
|
||||
* scan through the matching entries until we find that segment
|
||||
* reference or we run of matching entries.
|
||||
*/
|
||||
if (ref && memcmp(ref, &le->ref, sizeof(*ref))) {
|
||||
off += le16_to_cpu(le->size);
|
||||
le = Add2Ptr(al->le, off);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* Save on stack the size of 'le'. */
|
||||
size = le16_to_cpu(le->size);
|
||||
/* Delete the le. */
|
||||
memmove(le, Add2Ptr(le, size), al->size - (off + size));
|
||||
|
||||
al->size -= size;
|
||||
al->dirty = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int al_update(struct ntfs_inode *ni, int sync)
|
||||
{
|
||||
int err;
|
||||
|
205
fs/ntfs3/file.c
205
fs/ntfs3/file.c
@ -82,13 +82,14 @@ int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct fileattr *fa)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
u32 flags = fa->flags;
|
||||
unsigned int new_fl = 0;
|
||||
|
||||
if (fileattr_has_fsx(fa))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL))
|
||||
if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_COMPR_FL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (flags & FS_IMMUTABLE_FL)
|
||||
@ -97,6 +98,15 @@ int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
if (flags & FS_APPEND_FL)
|
||||
new_fl |= S_APPEND;
|
||||
|
||||
/* Allowed to change compression for empty files and for directories only. */
|
||||
if (!is_dedup(ni) && !is_encrypted(ni) &&
|
||||
(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
|
||||
/* Change compress state. */
|
||||
int err = ni_set_compress(inode, flags & FS_COMPR_FL);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND);
|
||||
|
||||
inode_set_ctime_current(inode);
|
||||
@ -407,6 +417,42 @@ static int ntfs_extend(struct inode *inode, loff_t pos, size_t count,
|
||||
err = 0;
|
||||
}
|
||||
|
||||
if (file && is_sparsed(ni)) {
|
||||
/*
|
||||
* This code optimizes large writes to sparse file.
|
||||
* TODO: merge this fragment with fallocate fragment.
|
||||
*/
|
||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||
CLST vcn = pos >> sbi->cluster_bits;
|
||||
CLST cend = bytes_to_cluster(sbi, end);
|
||||
CLST cend_v = bytes_to_cluster(sbi, ni->i_valid);
|
||||
CLST lcn, clen;
|
||||
bool new;
|
||||
|
||||
if (cend_v > cend)
|
||||
cend_v = cend;
|
||||
|
||||
/*
|
||||
* Allocate and zero new clusters.
|
||||
* Zeroing these clusters may be too long.
|
||||
*/
|
||||
for (; vcn < cend_v; vcn += clen) {
|
||||
err = attr_data_get_block(ni, vcn, cend_v - vcn, &lcn,
|
||||
&clen, &new, true);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* Allocate but not zero new clusters.
|
||||
*/
|
||||
for (; vcn < cend; vcn += clen) {
|
||||
err = attr_data_get_block(ni, vcn, cend - vcn, &lcn,
|
||||
&clen, &new, false);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
@ -483,7 +529,7 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size)
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_fallocate
|
||||
* ntfs_fallocate - file_operations::ntfs_fallocate
|
||||
*
|
||||
* Preallocate space for a file. This implements ntfs's fallocate file
|
||||
* operation, which gets called from sys_fallocate system call. User
|
||||
@ -618,6 +664,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
|
||||
ni_lock(ni);
|
||||
err = attr_collapse_range(ni, vbo, len);
|
||||
ni_unlock(ni);
|
||||
if (err)
|
||||
goto out;
|
||||
} else if (mode & FALLOC_FL_INSERT_RANGE) {
|
||||
/* Check new size. */
|
||||
err = inode_newsize_ok(inode, new_size);
|
||||
@ -740,10 +788,10 @@ out:
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs3_setattr - inode_operations::setattr
|
||||
* ntfs_setattr - inode_operations::setattr
|
||||
*/
|
||||
int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
@ -803,10 +851,12 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
/*
|
||||
* check_read_restriction:
|
||||
* common code for ntfs_file_read_iter and ntfs_file_splice_read
|
||||
*/
|
||||
static int check_read_restriction(struct inode *inode)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
@ -817,56 +867,58 @@ static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NTFS3_LZX_XPRESS
|
||||
if (ni->ni_flags & NI_FLAG_COMPRESSED_MASK) {
|
||||
ntfs_inode_warn(
|
||||
inode,
|
||||
"activate CONFIG_NTFS3_LZX_XPRESS to read external compressed files");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is_dedup(ni)) {
|
||||
ntfs_inode_warn(inode, "read deduplicated not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_file_read_iter - file_operations::read_iter
|
||||
*/
|
||||
static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
ssize_t err;
|
||||
|
||||
err = check_read_restriction(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (is_compressed(ni) && (iocb->ki_flags & IOCB_DIRECT)) {
|
||||
ntfs_inode_warn(inode, "direct i/o + compressed not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NTFS3_LZX_XPRESS
|
||||
if (ni->ni_flags & NI_FLAG_COMPRESSED_MASK) {
|
||||
ntfs_inode_warn(
|
||||
inode,
|
||||
"activate CONFIG_NTFS3_LZX_XPRESS to read external compressed files");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is_dedup(ni)) {
|
||||
ntfs_inode_warn(inode, "read deduplicated not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return generic_file_read_iter(iocb, iter);
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_file_splice_read - file_operations::splice_read
|
||||
*/
|
||||
static ssize_t ntfs_file_splice_read(struct file *in, loff_t *ppos,
|
||||
struct pipe_inode_info *pipe, size_t len,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *inode = file_inode(in);
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
ssize_t err;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
if (is_encrypted(ni)) {
|
||||
ntfs_inode_warn(inode, "encrypted i/o not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NTFS3_LZX_XPRESS
|
||||
if (ni->ni_flags & NI_FLAG_COMPRESSED_MASK) {
|
||||
ntfs_inode_warn(
|
||||
inode,
|
||||
"activate CONFIG_NTFS3_LZX_XPRESS to read external compressed files");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is_dedup(ni)) {
|
||||
ntfs_inode_warn(inode, "read deduplicated not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
err = check_read_restriction(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return filemap_splice_read(in, ppos, pipe, len, flags);
|
||||
}
|
||||
@ -1134,14 +1186,11 @@ out:
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_file_write_iter - file_operations::write_iter
|
||||
* check_write_restriction:
|
||||
* common code for ntfs_file_write_iter and ntfs_file_splice_write
|
||||
*/
|
||||
static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
static int check_write_restriction(struct inode *inode)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
ssize_t ret;
|
||||
int err;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
@ -1152,13 +1201,31 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (is_compressed(ni) && (iocb->ki_flags & IOCB_DIRECT)) {
|
||||
ntfs_inode_warn(inode, "direct i/o + compressed not supported");
|
||||
if (is_dedup(ni)) {
|
||||
ntfs_inode_warn(inode, "write into deduplicated not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (is_dedup(ni)) {
|
||||
ntfs_inode_warn(inode, "write into deduplicated not supported");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_file_write_iter - file_operations::write_iter
|
||||
*/
|
||||
static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
ssize_t ret;
|
||||
int err;
|
||||
|
||||
err = check_write_restriction(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (is_compressed(ni) && (iocb->ki_flags & IOCB_DIRECT)) {
|
||||
ntfs_inode_warn(inode, "direct i/o + compressed not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@ -1246,7 +1313,14 @@ static int ntfs_file_release(struct inode *inode, struct file *file)
|
||||
/* If we are last writer on the inode, drop the block reservation. */
|
||||
if (sbi->options->prealloc &&
|
||||
((file->f_mode & FMODE_WRITE) &&
|
||||
atomic_read(&inode->i_writecount) == 1)) {
|
||||
atomic_read(&inode->i_writecount) == 1)
|
||||
/*
|
||||
* The only file when inode->i_fop = &ntfs_file_operations and
|
||||
* init_rwsem(&ni->file.run_lock) is not called explicitly is MFT.
|
||||
*
|
||||
* Add additional check here.
|
||||
*/
|
||||
&& inode->i_ino != MFT_REC_MFT) {
|
||||
ni_lock(ni);
|
||||
down_write(&ni->file.run_lock);
|
||||
|
||||
@ -1282,10 +1356,27 @@ int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_file_splice_write - file_operations::splice_write
|
||||
*/
|
||||
static ssize_t ntfs_file_splice_write(struct pipe_inode_info *pipe,
|
||||
struct file *file, loff_t *ppos,
|
||||
size_t len, unsigned int flags)
|
||||
{
|
||||
ssize_t err;
|
||||
struct inode *inode = file_inode(file);
|
||||
|
||||
err = check_write_restriction(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return iter_file_splice_write(pipe, file, ppos, len, flags);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
const struct inode_operations ntfs_file_inode_operations = {
|
||||
.getattr = ntfs_getattr,
|
||||
.setattr = ntfs3_setattr,
|
||||
.setattr = ntfs_setattr,
|
||||
.listxattr = ntfs_listxattr,
|
||||
.get_acl = ntfs_get_acl,
|
||||
.set_acl = ntfs_set_acl,
|
||||
@ -1303,10 +1394,10 @@ const struct file_operations ntfs_file_operations = {
|
||||
.compat_ioctl = ntfs_compat_ioctl,
|
||||
#endif
|
||||
.splice_read = ntfs_file_splice_read,
|
||||
.splice_write = ntfs_file_splice_write,
|
||||
.mmap = ntfs_file_mmap,
|
||||
.open = ntfs_file_open,
|
||||
.fsync = generic_file_fsync,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.fallocate = ntfs_fallocate,
|
||||
.release = ntfs_file_release,
|
||||
};
|
||||
|
@ -102,7 +102,9 @@ void ni_clear(struct ntfs_inode *ni)
|
||||
{
|
||||
struct rb_node *node;
|
||||
|
||||
if (!ni->vfs_inode.i_nlink && ni->mi.mrec && is_rec_inuse(ni->mi.mrec))
|
||||
if (!ni->vfs_inode.i_nlink && ni->mi.mrec &&
|
||||
is_rec_inuse(ni->mi.mrec) &&
|
||||
!(ni->mi.sbi->flags & NTFS_FLAGS_LOG_REPLAYING))
|
||||
ni_delete_all(ni);
|
||||
|
||||
al_destroy(ni);
|
||||
@ -1900,13 +1902,13 @@ enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
|
||||
/*
|
||||
* fiemap_fill_next_extent_k - a copy of fiemap_fill_next_extent
|
||||
* but it accepts kernel address for fi_extents_start
|
||||
* but it uses 'fe_k' instead of fieinfo->fi_extents_start
|
||||
*/
|
||||
static int fiemap_fill_next_extent_k(struct fiemap_extent_info *fieinfo,
|
||||
u64 logical, u64 phys, u64 len, u32 flags)
|
||||
struct fiemap_extent *fe_k, u64 logical,
|
||||
u64 phys, u64 len, u32 flags)
|
||||
{
|
||||
struct fiemap_extent extent;
|
||||
struct fiemap_extent __user *dest = fieinfo->fi_extents_start;
|
||||
|
||||
/* only count the extents */
|
||||
if (fieinfo->fi_extents_max == 0) {
|
||||
@ -1930,8 +1932,7 @@ static int fiemap_fill_next_extent_k(struct fiemap_extent_info *fieinfo,
|
||||
extent.fe_length = len;
|
||||
extent.fe_flags = flags;
|
||||
|
||||
dest += fieinfo->fi_extents_mapped;
|
||||
memcpy(dest, &extent, sizeof(extent));
|
||||
memcpy(fe_k + fieinfo->fi_extents_mapped, &extent, sizeof(extent));
|
||||
|
||||
fieinfo->fi_extents_mapped++;
|
||||
if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max)
|
||||
@ -1949,7 +1950,6 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
__u64 vbo, __u64 len)
|
||||
{
|
||||
int err = 0;
|
||||
struct fiemap_extent __user *fe_u = fieinfo->fi_extents_start;
|
||||
struct fiemap_extent *fe_k = NULL;
|
||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||
u8 cluster_bits = sbi->cluster_bits;
|
||||
@ -2008,7 +2008,6 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
fieinfo->fi_extents_start = fe_k;
|
||||
|
||||
end = vbo + len;
|
||||
alloc_size = le64_to_cpu(attr->nres.alloc_size);
|
||||
@ -2098,8 +2097,8 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
if (vbo + dlen >= end)
|
||||
flags |= FIEMAP_EXTENT_LAST;
|
||||
|
||||
err = fiemap_fill_next_extent_k(fieinfo, vbo, lbo, dlen,
|
||||
flags);
|
||||
err = fiemap_fill_next_extent_k(fieinfo, fe_k, vbo, lbo,
|
||||
dlen, flags);
|
||||
|
||||
if (err < 0)
|
||||
break;
|
||||
@ -2120,7 +2119,7 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
if (vbo + bytes >= end)
|
||||
flags |= FIEMAP_EXTENT_LAST;
|
||||
|
||||
err = fiemap_fill_next_extent_k(fieinfo, vbo, lbo, bytes,
|
||||
err = fiemap_fill_next_extent_k(fieinfo, fe_k, vbo, lbo, bytes,
|
||||
flags);
|
||||
if (err < 0)
|
||||
break;
|
||||
@ -2137,15 +2136,13 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
/*
|
||||
* Copy to user memory out of lock
|
||||
*/
|
||||
if (copy_to_user(fe_u, fe_k,
|
||||
if (copy_to_user(fieinfo->fi_extents_start, fe_k,
|
||||
fieinfo->fi_extents_max *
|
||||
sizeof(struct fiemap_extent))) {
|
||||
err = -EFAULT;
|
||||
}
|
||||
|
||||
out:
|
||||
/* Restore original pointer. */
|
||||
fieinfo->fi_extents_start = fe_u;
|
||||
kfree(fe_k);
|
||||
return err;
|
||||
}
|
||||
@ -3455,3 +3452,75 @@ out:
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ni_set_compress
|
||||
*
|
||||
* Helper for 'ntfs_fileattr_set'.
|
||||
* Changes compression for empty files and directories only.
|
||||
*/
|
||||
int ni_set_compress(struct inode *inode, bool compr)
|
||||
{
|
||||
int err;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
struct ATTR_STD_INFO *std;
|
||||
const char *bad_inode;
|
||||
|
||||
if (is_compressed(ni) == !!compr)
|
||||
return 0;
|
||||
|
||||
if (is_sparsed(ni)) {
|
||||
/* sparse and compress not compatible. */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) {
|
||||
/*Skip other inodes. (symlink,fifo,...) */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
bad_inode = NULL;
|
||||
|
||||
ni_lock(ni);
|
||||
|
||||
std = ni_std(ni);
|
||||
if (!std) {
|
||||
bad_inode = "no std";
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
err = attr_set_compress(ni, compr);
|
||||
if (err) {
|
||||
if (err == -ENOENT) {
|
||||
/* Fix on the fly? */
|
||||
/* Each file must contain data attribute. */
|
||||
bad_inode = "no data attribute";
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ni->std_fa = std->fa;
|
||||
if (compr)
|
||||
std->fa |= FILE_ATTRIBUTE_COMPRESSED;
|
||||
else
|
||||
std->fa &= ~FILE_ATTRIBUTE_COMPRESSED;
|
||||
|
||||
if (ni->std_fa != std->fa) {
|
||||
ni->std_fa = std->fa;
|
||||
ni->mi.dirty = true;
|
||||
}
|
||||
/* update duplicate information and directory entries in ni_write_inode.*/
|
||||
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
ni_unlock(ni);
|
||||
if (bad_inode) {
|
||||
ntfs_bad_inode(inode, bad_inode);
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -609,14 +609,29 @@ static inline void add_client(struct CLIENT_REC *ca, u16 index, __le16 *head)
|
||||
*head = cpu_to_le16(index);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enumerate restart table.
|
||||
*
|
||||
* @t - table to enumerate.
|
||||
* @c - current enumerated element.
|
||||
*
|
||||
* enumeration starts with @c == NULL
|
||||
* returns next element or NULL
|
||||
*/
|
||||
static inline void *enum_rstbl(struct RESTART_TABLE *t, void *c)
|
||||
{
|
||||
__le32 *e;
|
||||
u32 bprt;
|
||||
u16 rsize = t ? le16_to_cpu(t->size) : 0;
|
||||
u16 rsize;
|
||||
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
rsize = le16_to_cpu(t->size);
|
||||
|
||||
if (!c) {
|
||||
if (!t || !t->total)
|
||||
/* start enumeration. */
|
||||
if (!t->total)
|
||||
return NULL;
|
||||
e = Add2Ptr(t, sizeof(struct RESTART_TABLE));
|
||||
} else {
|
||||
|
@ -536,11 +536,15 @@ struct inode *ntfs_iget5(struct super_block *sb, const struct MFT_REF *ref,
|
||||
if (inode->i_state & I_NEW)
|
||||
inode = ntfs_read_mft(inode, name, ref);
|
||||
else if (ref->seq != ntfs_i(inode)->mi.mrec->seq) {
|
||||
/* Inode overlaps? */
|
||||
_ntfs_bad_inode(inode);
|
||||
/*
|
||||
* Sequence number is not expected.
|
||||
* Looks like inode was reused but caller uses the old reference
|
||||
*/
|
||||
iput(inode);
|
||||
inode = ERR_PTR(-ESTALE);
|
||||
}
|
||||
|
||||
if (IS_ERR(inode) && name)
|
||||
if (IS_ERR(inode))
|
||||
ntfs_set_state(sb->s_fs_info, NTFS_DIRTY_ERROR);
|
||||
|
||||
return inode;
|
||||
@ -605,7 +609,8 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo,
|
||||
|
||||
bytes = ((u64)len << cluster_bits) - off;
|
||||
|
||||
if (lcn == SPARSE_LCN) {
|
||||
if (lcn >= sbi->used.bitmap.nbits) {
|
||||
/* This case includes resident/compressed/sparse. */
|
||||
if (!create) {
|
||||
if (bh->b_size > bytes)
|
||||
bh->b_size = bytes;
|
||||
@ -1672,7 +1677,10 @@ out6:
|
||||
attr = ni_find_attr(ni, NULL, NULL, ATTR_EA, NULL, 0, NULL, NULL);
|
||||
if (attr && attr->non_res) {
|
||||
/* Delete ATTR_EA, if non-resident. */
|
||||
attr_set_size(ni, ATTR_EA, NULL, 0, NULL, 0, NULL, false, NULL);
|
||||
struct runs_tree run;
|
||||
run_init(&run);
|
||||
attr_set_size(ni, ATTR_EA, NULL, 0, &run, 0, NULL, false, NULL);
|
||||
run_close(&run);
|
||||
}
|
||||
|
||||
if (rp_inserted)
|
||||
@ -2076,7 +2084,7 @@ static const char *ntfs_get_link(struct dentry *de, struct inode *inode,
|
||||
// clang-format off
|
||||
const struct inode_operations ntfs_link_inode_operations = {
|
||||
.get_link = ntfs_get_link,
|
||||
.setattr = ntfs3_setattr,
|
||||
.setattr = ntfs_setattr,
|
||||
.listxattr = ntfs_listxattr,
|
||||
};
|
||||
|
||||
|
@ -512,8 +512,7 @@ static int lzx_decompress_block(const struct lzx_decompressor *d,
|
||||
* the same code. (For R0, the swap is a no-op.)
|
||||
*/
|
||||
match_offset = recent_offsets[offset_slot];
|
||||
recent_offsets[offset_slot] = recent_offsets[0];
|
||||
recent_offsets[0] = match_offset;
|
||||
swap(recent_offsets[offset_slot], recent_offsets[0]);
|
||||
} else {
|
||||
/* Explicit offset */
|
||||
|
||||
|
@ -236,6 +236,9 @@ static inline ssize_t decompress_chunk(u8 *unc, u8 *unc_end, const u8 *cmpr,
|
||||
|
||||
/* Do decompression until pointers are inside range. */
|
||||
while (up < unc_end && cmpr < cmpr_end) {
|
||||
// return err if more than LZNT_CHUNK_SIZE bytes are written
|
||||
if (up - unc > LZNT_CHUNK_SIZE)
|
||||
return -EINVAL;
|
||||
/* Correct index */
|
||||
while (unc + s_max_off[index] < up)
|
||||
index += 1;
|
||||
|
@ -81,7 +81,7 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
if (err < 0)
|
||||
inode = ERR_PTR(err);
|
||||
else {
|
||||
ni_lock(ni);
|
||||
ni_lock_dir(ni);
|
||||
inode = dir_search_u(dir, uni, NULL);
|
||||
ni_unlock(ni);
|
||||
}
|
||||
@ -395,7 +395,7 @@ static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name)
|
||||
/*
|
||||
* Try slow way with current upcase table
|
||||
*/
|
||||
uni = __getname();
|
||||
uni = kmem_cache_alloc(names_cachep, GFP_NOWAIT);
|
||||
if (!uni)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -417,7 +417,7 @@ static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name)
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
__putname(uni);
|
||||
kmem_cache_free(names_cachep, uni);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -503,7 +503,7 @@ const struct inode_operations ntfs_dir_inode_operations = {
|
||||
.rename = ntfs_rename,
|
||||
.get_acl = ntfs_get_acl,
|
||||
.set_acl = ntfs_set_acl,
|
||||
.setattr = ntfs3_setattr,
|
||||
.setattr = ntfs_setattr,
|
||||
.getattr = ntfs_getattr,
|
||||
.listxattr = ntfs_listxattr,
|
||||
.fiemap = ntfs_fiemap,
|
||||
@ -512,7 +512,7 @@ const struct inode_operations ntfs_dir_inode_operations = {
|
||||
};
|
||||
|
||||
const struct inode_operations ntfs_special_inode_operations = {
|
||||
.setattr = ntfs3_setattr,
|
||||
.setattr = ntfs_setattr,
|
||||
.getattr = ntfs_getattr,
|
||||
.listxattr = ntfs_listxattr,
|
||||
.get_acl = ntfs_get_acl,
|
||||
|
@ -334,7 +334,7 @@ struct mft_inode {
|
||||
|
||||
/* Nested class for ntfs_inode::ni_lock. */
|
||||
enum ntfs_inode_mutex_lock_class {
|
||||
NTFS_INODE_MUTEX_DIRTY,
|
||||
NTFS_INODE_MUTEX_DIRTY = 1,
|
||||
NTFS_INODE_MUTEX_SECURITY,
|
||||
NTFS_INODE_MUTEX_OBJID,
|
||||
NTFS_INODE_MUTEX_REPARSE,
|
||||
@ -453,6 +453,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
|
||||
int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
|
||||
int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size);
|
||||
int attr_force_nonresident(struct ntfs_inode *ni);
|
||||
int attr_set_compress(struct ntfs_inode *ni, bool compr);
|
||||
|
||||
/* Functions from attrlist.c */
|
||||
void al_destroy(struct ntfs_inode *ni);
|
||||
@ -471,8 +472,6 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
|
||||
u8 name_len, CLST svcn, __le16 id, const struct MFT_REF *ref,
|
||||
struct ATTR_LIST_ENTRY **new_le);
|
||||
bool al_remove_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le);
|
||||
bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn,
|
||||
const __le16 *name, u8 name_len, const struct MFT_REF *ref);
|
||||
int al_update(struct ntfs_inode *ni, int sync);
|
||||
static inline size_t al_aligned(size_t size)
|
||||
{
|
||||
@ -502,8 +501,8 @@ int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct fileattr *fa);
|
||||
int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, u32 flags);
|
||||
int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr);
|
||||
int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr);
|
||||
int ntfs_file_open(struct inode *inode, struct file *file);
|
||||
int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
__u64 start, __u64 len);
|
||||
@ -588,6 +587,7 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
|
||||
bool *is_bad);
|
||||
|
||||
bool ni_is_dirty(struct inode *inode);
|
||||
int ni_set_compress(struct inode *inode, bool compr);
|
||||
|
||||
/* Globals from fslog.c */
|
||||
bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes);
|
||||
|
@ -223,29 +223,21 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
prev_type = 0;
|
||||
attr = Add2Ptr(rec, off);
|
||||
} else {
|
||||
/* Check if input attr inside record. */
|
||||
/*
|
||||
* We don't need to check previous attr here. There is
|
||||
* a bounds checking in the previous round.
|
||||
*/
|
||||
off = PtrOffset(rec, attr);
|
||||
if (off >= used)
|
||||
return NULL;
|
||||
|
||||
asize = le32_to_cpu(attr->size);
|
||||
if (asize < SIZEOF_RESIDENT) {
|
||||
/* Impossible 'cause we should not return such attribute. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Overflow check. */
|
||||
if (off + asize < off)
|
||||
return NULL;
|
||||
|
||||
prev_type = le32_to_cpu(attr->type);
|
||||
attr = Add2Ptr(attr, asize);
|
||||
off += asize;
|
||||
}
|
||||
|
||||
asize = le32_to_cpu(attr->size);
|
||||
|
||||
/* Can we use the first field (attr->type). */
|
||||
/* NOTE: this code also checks attr->size availability. */
|
||||
if (off + 8 > used) {
|
||||
static_assert(ALIGN(sizeof(enum ATTR_TYPE), 8) == 8);
|
||||
return NULL;
|
||||
@ -265,6 +257,8 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
if (t32 < prev_type)
|
||||
return NULL;
|
||||
|
||||
asize = le32_to_cpu(attr->size);
|
||||
|
||||
/* Check overflow and boundary. */
|
||||
if (off + asize < off || off + asize > used)
|
||||
return NULL;
|
||||
@ -293,6 +287,10 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
if (attr->non_res != 1)
|
||||
return NULL;
|
||||
|
||||
/* Can we use memory including attr->nres.valid_size? */
|
||||
if (asize < SIZEOF_NONRESIDENT)
|
||||
return NULL;
|
||||
|
||||
t16 = le16_to_cpu(attr->nres.run_off);
|
||||
if (t16 > asize)
|
||||
return NULL;
|
||||
@ -319,7 +317,8 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
|
||||
if (!attr->nres.svcn && is_attr_ext(attr)) {
|
||||
/* First segment of sparse/compressed attribute */
|
||||
if (asize + 8 < SIZEOF_NONRESIDENT_EX)
|
||||
/* Can we use memory including attr->nres.total_size? */
|
||||
if (asize < SIZEOF_NONRESIDENT_EX)
|
||||
return NULL;
|
||||
|
||||
tot_size = le64_to_cpu(attr->nres.total_size);
|
||||
@ -329,10 +328,10 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
if (tot_size > alloc_size)
|
||||
return NULL;
|
||||
} else {
|
||||
if (asize + 8 < SIZEOF_NONRESIDENT)
|
||||
if (attr->nres.c_unit)
|
||||
return NULL;
|
||||
|
||||
if (attr->nres.c_unit)
|
||||
if (alloc_size > mi->sbi->volume.size)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -959,7 +959,7 @@ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
||||
* Large positive number requires to store 5 bytes
|
||||
* e.g.: 05 FF 7E FF FF 00 00 00
|
||||
*/
|
||||
if (size_size > 8)
|
||||
if (size_size > sizeof(len))
|
||||
return -EINVAL;
|
||||
|
||||
len = run_unpack_s64(run_buf, size_size, 0);
|
||||
@ -971,7 +971,7 @@ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
||||
|
||||
if (!offset_size)
|
||||
lcn = SPARSE_LCN64;
|
||||
else if (offset_size <= 8) {
|
||||
else if (offset_size <= sizeof(s64)) {
|
||||
s64 dlcn;
|
||||
|
||||
/* Initial value of dlcn is -1 or 0. */
|
||||
@ -984,8 +984,10 @@ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
||||
return -EINVAL;
|
||||
lcn = prev_lcn + dlcn;
|
||||
prev_lcn = lcn;
|
||||
} else
|
||||
} else {
|
||||
/* The size of 'dlcn' can't be > 8. */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
next_vcn = vcn64 + len;
|
||||
/* Check boundary. */
|
||||
|
@ -90,7 +90,7 @@ void ntfs_printk(const struct super_block *sb, const char *fmt, ...)
|
||||
level = printk_get_level(fmt);
|
||||
vaf.fmt = printk_skip_level(fmt);
|
||||
vaf.va = &args;
|
||||
printk("%c%cntfs3: %s: %pV\n", KERN_SOH_ASCII, level, sb->s_id, &vaf);
|
||||
printk("%c%cntfs3(%s): %pV\n", KERN_SOH_ASCII, level, sb->s_id, &vaf);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
@ -124,10 +124,15 @@ void ntfs_inode_printk(struct inode *inode, const char *fmt, ...)
|
||||
struct dentry *de = d_find_alias(inode);
|
||||
|
||||
if (de) {
|
||||
int len;
|
||||
spin_lock(&de->d_lock);
|
||||
snprintf(name, sizeof(s_name_buf), " \"%s\"",
|
||||
de->d_name.name);
|
||||
len = snprintf(name, sizeof(s_name_buf), " \"%s\"",
|
||||
de->d_name.name);
|
||||
spin_unlock(&de->d_lock);
|
||||
if (len <= 0)
|
||||
name[0] = 0;
|
||||
else if (len >= sizeof(s_name_buf))
|
||||
name[sizeof(s_name_buf) - 1] = 0;
|
||||
} else {
|
||||
name[0] = 0;
|
||||
}
|
||||
@ -140,7 +145,7 @@ void ntfs_inode_printk(struct inode *inode, const char *fmt, ...)
|
||||
vaf.fmt = printk_skip_level(fmt);
|
||||
vaf.va = &args;
|
||||
|
||||
printk("%c%cntfs3: %s: ino=%lx,%s %pV\n", KERN_SOH_ASCII, level,
|
||||
printk("%c%cntfs3(%s): ino=%lx,%s %pV\n", KERN_SOH_ASCII, level,
|
||||
sb->s_id, inode->i_ino, name ? name : "", &vaf);
|
||||
|
||||
va_end(args);
|
||||
@ -259,23 +264,23 @@ enum Opt {
|
||||
|
||||
// clang-format off
|
||||
static const struct fs_parameter_spec ntfs_fs_parameters[] = {
|
||||
fsparam_uid("uid", Opt_uid),
|
||||
fsparam_gid("gid", Opt_gid),
|
||||
fsparam_u32oct("umask", Opt_umask),
|
||||
fsparam_u32oct("dmask", Opt_dmask),
|
||||
fsparam_u32oct("fmask", Opt_fmask),
|
||||
fsparam_flag_no("sys_immutable", Opt_immutable),
|
||||
fsparam_flag_no("discard", Opt_discard),
|
||||
fsparam_flag_no("force", Opt_force),
|
||||
fsparam_flag_no("sparse", Opt_sparse),
|
||||
fsparam_flag_no("hidden", Opt_nohidden),
|
||||
fsparam_flag_no("hide_dot_files", Opt_hide_dot_files),
|
||||
fsparam_flag_no("windows_names", Opt_windows_names),
|
||||
fsparam_flag_no("showmeta", Opt_showmeta),
|
||||
fsparam_flag_no("acl", Opt_acl),
|
||||
fsparam_string("iocharset", Opt_iocharset),
|
||||
fsparam_flag_no("prealloc", Opt_prealloc),
|
||||
fsparam_flag_no("case", Opt_nocase),
|
||||
fsparam_uid("uid", Opt_uid),
|
||||
fsparam_gid("gid", Opt_gid),
|
||||
fsparam_u32oct("umask", Opt_umask),
|
||||
fsparam_u32oct("dmask", Opt_dmask),
|
||||
fsparam_u32oct("fmask", Opt_fmask),
|
||||
fsparam_flag("sys_immutable", Opt_immutable),
|
||||
fsparam_flag("discard", Opt_discard),
|
||||
fsparam_flag("force", Opt_force),
|
||||
fsparam_flag("sparse", Opt_sparse),
|
||||
fsparam_flag("nohidden", Opt_nohidden),
|
||||
fsparam_flag("hide_dot_files", Opt_hide_dot_files),
|
||||
fsparam_flag("windows_names", Opt_windows_names),
|
||||
fsparam_flag("showmeta", Opt_showmeta),
|
||||
fsparam_flag("acl", Opt_acl),
|
||||
fsparam_string("iocharset", Opt_iocharset),
|
||||
fsparam_flag("prealloc", Opt_prealloc),
|
||||
fsparam_flag("nocase", Opt_nocase),
|
||||
{}
|
||||
};
|
||||
// clang-format on
|
||||
@ -345,28 +350,28 @@ static int ntfs_fs_parse_param(struct fs_context *fc,
|
||||
opts->fmask = 1;
|
||||
break;
|
||||
case Opt_immutable:
|
||||
opts->sys_immutable = result.negated ? 0 : 1;
|
||||
opts->sys_immutable = 1;
|
||||
break;
|
||||
case Opt_discard:
|
||||
opts->discard = result.negated ? 0 : 1;
|
||||
opts->discard = 1;
|
||||
break;
|
||||
case Opt_force:
|
||||
opts->force = result.negated ? 0 : 1;
|
||||
opts->force = 1;
|
||||
break;
|
||||
case Opt_sparse:
|
||||
opts->sparse = result.negated ? 0 : 1;
|
||||
opts->sparse = 1;
|
||||
break;
|
||||
case Opt_nohidden:
|
||||
opts->nohidden = result.negated ? 1 : 0;
|
||||
opts->nohidden = 1;
|
||||
break;
|
||||
case Opt_hide_dot_files:
|
||||
opts->hide_dot_files = result.negated ? 0 : 1;
|
||||
opts->hide_dot_files = 1;
|
||||
break;
|
||||
case Opt_windows_names:
|
||||
opts->windows_names = result.negated ? 0 : 1;
|
||||
opts->windows_names = 1;
|
||||
break;
|
||||
case Opt_showmeta:
|
||||
opts->showmeta = result.negated ? 0 : 1;
|
||||
opts->showmeta = 1;
|
||||
break;
|
||||
case Opt_acl:
|
||||
if (!result.negated)
|
||||
@ -385,10 +390,10 @@ static int ntfs_fs_parse_param(struct fs_context *fc,
|
||||
param->string = NULL;
|
||||
break;
|
||||
case Opt_prealloc:
|
||||
opts->prealloc = result.negated ? 0 : 1;
|
||||
opts->prealloc = 1;
|
||||
break;
|
||||
case Opt_nocase:
|
||||
opts->nocase = result.negated ? 1 : 0;
|
||||
opts->nocase = 1;
|
||||
break;
|
||||
default:
|
||||
/* Should not be here unless we forget add case. */
|
||||
@ -1491,11 +1496,10 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
{
|
||||
const __le16 *src = sbi->upcase;
|
||||
u16 *dst = sbi->upcase;
|
||||
|
||||
for (i = 0; i < 0x10000; i++)
|
||||
*dst++ = le16_to_cpu(*src++);
|
||||
__swab16s(dst++);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -705,7 +705,7 @@ int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode,
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ntfs_acl_chmod - Helper for ntfs3_setattr().
|
||||
* ntfs_acl_chmod - Helper for ntfs_setattr().
|
||||
*/
|
||||
int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user