Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…up/linux-ntfs3

Pull ntfs3 updates from Konstantin Komarov:
 "Fixes:
   - reusing of the file index (could cause the file to be trimmed)
   - infinite dir enumeration
   - taking DOS names into account during link counting
   - le32_to_cpu conversion, 32 bit overflow, NULL check
   - some code was refactored

  Changes:
   - removed max link count info display during driver init

  Remove:
   - atomic_open has been removed for lack of use"

* tag 'ntfs3_for_6.10' of https://github.com/Paragon-Software-Group/linux-ntfs3:
  fs/ntfs3: Break dir enumeration if directory contents error
  fs/ntfs3: Fix case when index is reused during tree transformation
  fs/ntfs3: Mark volume as dirty if xattr is broken
  fs/ntfs3: Always make file nonresident on fallocate call
  fs/ntfs3: Redesign ntfs_create_inode to return error code instead of inode
  fs/ntfs3: Use variable length array instead of fixed size
  fs/ntfs3: Use 64 bit variable to avoid 32 bit overflow
  fs/ntfs3: Check 'folio' pointer for NULL
  fs/ntfs3: Missed le32_to_cpu conversion
  fs/ntfs3: Remove max link count info display during driver init
  fs/ntfs3: Taking DOS names into account during link counting
  fs/ntfs3: remove atomic_open
  fs/ntfs3: use kcalloc() instead of kzalloc()
  • Loading branch information
torvalds committed May 25, 2024
2 parents 6c8b1a2 + 302e9dc commit 89b61ca
Show file tree
Hide file tree
Showing 13 changed files with 98 additions and 154 deletions.
32 changes: 32 additions & 0 deletions fs/ntfs3/attrib.c
Original file line number Diff line number Diff line change
Expand Up @@ -2558,3 +2558,35 @@ int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)

goto out;
}

/*
* attr_force_nonresident
*
* Convert default data attribute into non resident form.
*/
int attr_force_nonresident(struct ntfs_inode *ni)
{
int err;
struct ATTRIB *attr;
struct ATTR_LIST_ENTRY *le = NULL;
struct mft_inode *mi;

attr = ni_find_attr(ni, NULL, &le, ATTR_DATA, NULL, 0, NULL, &mi);
if (!attr) {
ntfs_bad_inode(&ni->vfs_inode, "no data attribute");
return -ENOENT;
}

if (attr->non_res) {
/* Already non resident. */
return 0;
}

down_write(&ni->file.run_lock);
err = attr_make_nonresident(ni, attr, le, mi,
le32_to_cpu(attr->res.data_size),
&ni->file.run, &attr, NULL);
up_write(&ni->file.run_lock);

return err;
}
1 change: 1 addition & 0 deletions fs/ntfs3/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx)
vbo = (u64)bit << index_bits;
if (vbo >= i_size) {
ntfs_inode_err(dir, "Looks like your dir is corrupt");
ctx->pos = eod;
err = -EINVAL;
goto out;
}
Expand Down
9 changes: 9 additions & 0 deletions fs/ntfs3/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,15 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
/* Check new size. */
u8 cluster_bits = sbi->cluster_bits;

/* Be sure file is non resident. */
if (is_resident(ni)) {
ni_lock(ni);
err = attr_force_nonresident(ni);
ni_unlock(ni);
if (err)
goto out;
}

/* generic/213: expected -ENOSPC instead of -EFBIG. */
if (!is_supported_holes) {
loff_t to_alloc = new_size - inode_get_bytes(inode);
Expand Down
2 changes: 1 addition & 1 deletion fs/ntfs3/frecord.c
Original file line number Diff line number Diff line change
Expand Up @@ -2636,7 +2636,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
goto out1;
}

pages_disk = kzalloc(npages_disk * sizeof(struct page *), GFP_NOFS);
pages_disk = kcalloc(npages_disk, sizeof(*pages_disk), GFP_NOFS);
if (!pages_disk) {
err = -ENOMEM;
goto out2;
Expand Down
5 changes: 3 additions & 2 deletions fs/ntfs3/fslog.c
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ static inline bool is_rst_area_valid(const struct RESTART_HDR *rhdr)
seq_bits -= 1;
}

if (seq_bits != ra->seq_num_bits)
if (seq_bits != le32_to_cpu(ra->seq_num_bits))
return false;

/* The log page data offset and record header length must be quad-aligned. */
Expand Down Expand Up @@ -1184,7 +1184,8 @@ static int read_log_page(struct ntfs_log *log, u32 vbo,
static int log_read_rst(struct ntfs_log *log, bool first,
struct restart_info *info)
{
u32 skip, vbo;
u32 skip;
u64 vbo;
struct RESTART_HDR *r_page = NULL;

/* Determine which restart area we are looking for. */
Expand Down
6 changes: 6 additions & 0 deletions fs/ntfs3/index.c
Original file line number Diff line number Diff line change
Expand Up @@ -1534,6 +1534,11 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
goto out1;
}

if (data_size <= le64_to_cpu(alloc->nres.data_size)) {
/* Reuse index. */
goto out;
}

/* Increase allocation. */
err = attr_set_size(ni, ATTR_ALLOC, in->name, in->name_len,
&indx->alloc_run, data_size, &data_size, true,
Expand All @@ -1547,6 +1552,7 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
if (in->name == I30_NAME)
i_size_write(&ni->vfs_inode, data_size);

out:
*vbn = bit << indx->idx2vbn_bits;

return 0;
Expand Down
46 changes: 26 additions & 20 deletions fs/ntfs3/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ static struct inode *ntfs_read_mft(struct inode *inode,
bool is_dir;
unsigned long ino = inode->i_ino;
u32 rp_fa = 0, asize, t32;
u16 roff, rsize, names = 0;
u16 roff, rsize, names = 0, links = 0;
const struct ATTR_FILE_NAME *fname = NULL;
const struct INDEX_ROOT *root;
struct REPARSE_DATA_BUFFER rp; // 0x18 bytes
Expand Down Expand Up @@ -200,11 +200,12 @@ static struct inode *ntfs_read_mft(struct inode *inode,
rsize < SIZEOF_ATTRIBUTE_FILENAME)
goto out;

names += 1;
fname = Add2Ptr(attr, roff);
if (fname->type == FILE_NAME_DOS)
goto next_attr;

names += 1;
links += 1;
if (name && name->len == fname->name_len &&
!ntfs_cmp_names_cpu(name, (struct le_str *)&fname->name_len,
NULL, false))
Expand Down Expand Up @@ -429,7 +430,7 @@ static struct inode *ntfs_read_mft(struct inode *inode,
ni->mi.dirty = true;
}

set_nlink(inode, names);
set_nlink(inode, links);

if (S_ISDIR(mode)) {
ni->std_fa |= FILE_ATTRIBUTE_DIRECTORY;
Expand Down Expand Up @@ -576,13 +577,18 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo,
clear_buffer_uptodate(bh);

if (is_resident(ni)) {
ni_lock(ni);
err = attr_data_read_resident(ni, &folio->page);
ni_unlock(ni);

if (!err)
set_buffer_uptodate(bh);
bh->b_blocknr = RESIDENT_LCN;
bh->b_size = block_size;
if (!folio) {
err = 0;
} else {
ni_lock(ni);
err = attr_data_read_resident(ni, &folio->page);
ni_unlock(ni);

if (!err)
set_buffer_uptodate(bh);
}
return err;
}

Expand Down Expand Up @@ -1216,11 +1222,10 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
*
* NOTE: if fnd != NULL (ntfs_atomic_open) then @dir is locked
*/
struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry,
const struct cpu_str *uni, umode_t mode,
dev_t dev, const char *symname, u32 size,
struct ntfs_fnd *fnd)
int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, const struct cpu_str *uni,
umode_t mode, dev_t dev, const char *symname, u32 size,
struct ntfs_fnd *fnd)
{
int err;
struct super_block *sb = dir->i_sb;
Expand All @@ -1245,6 +1250,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
struct REPARSE_DATA_BUFFER *rp = NULL;
bool rp_inserted = false;

/* New file will be resident or non resident. */
const bool new_file_resident = 1;

if (!fnd)
ni_lock_dir(dir_ni);

Expand Down Expand Up @@ -1484,7 +1492,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
attr->size = cpu_to_le32(SIZEOF_RESIDENT);
attr->name_off = SIZEOF_RESIDENT_LE;
attr->res.data_off = SIZEOF_RESIDENT_LE;
} else if (S_ISREG(mode)) {
} else if (!new_file_resident && S_ISREG(mode)) {
/*
* Regular file. Create empty non resident data attribute.
*/
Expand Down Expand Up @@ -1727,12 +1735,10 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
if (!fnd)
ni_unlock(dir_ni);

if (err)
return ERR_PTR(err);

unlock_new_inode(inode);
if (!err)
unlock_new_inode(inode);

return inode;
return err;
}

int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
Expand Down
121 changes: 8 additions & 113 deletions fs/ntfs3/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,8 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry,
static int ntfs_create(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, bool excl)
{
struct inode *inode;

inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFREG | mode, 0,
NULL, 0, NULL);

return IS_ERR(inode) ? PTR_ERR(inode) : 0;
return ntfs_create_inode(idmap, dir, dentry, NULL, S_IFREG | mode, 0,
NULL, 0, NULL);
}

/*
Expand All @@ -123,12 +119,8 @@ static int ntfs_create(struct mnt_idmap *idmap, struct inode *dir,
static int ntfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, dev_t rdev)
{
struct inode *inode;

inode = ntfs_create_inode(idmap, dir, dentry, NULL, mode, rdev, NULL, 0,
NULL);

return IS_ERR(inode) ? PTR_ERR(inode) : 0;
return ntfs_create_inode(idmap, dir, dentry, NULL, mode, rdev, NULL, 0,
NULL);
}

/*
Expand Down Expand Up @@ -200,15 +192,12 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, const char *symname)
{
u32 size = strlen(symname);
struct inode *inode;

if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
return -EIO;

inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFLNK | 0777, 0,
symname, size, NULL);

return IS_ERR(inode) ? PTR_ERR(inode) : 0;
return ntfs_create_inode(idmap, dir, dentry, NULL, S_IFLNK | 0777, 0,
symname, size, NULL);
}

/*
Expand All @@ -217,12 +206,8 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
static int ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode)
{
struct inode *inode;

inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0,
NULL, 0, NULL);

return IS_ERR(inode) ? PTR_ERR(inode) : 0;
return ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0,
NULL, 0, NULL);
}

/*
Expand Down Expand Up @@ -358,95 +343,6 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir,
return err;
}

/*
* ntfs_atomic_open
*
* inode_operations::atomic_open
*/
static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry,
struct file *file, u32 flags, umode_t mode)
{
int err;
struct inode *inode;
struct ntfs_fnd *fnd = NULL;
struct ntfs_inode *ni = ntfs_i(dir);
struct dentry *d = NULL;
struct cpu_str *uni = __getname();
bool locked = false;

if (!uni)
return -ENOMEM;

err = ntfs_nls_to_utf16(ni->mi.sbi, dentry->d_name.name,
dentry->d_name.len, uni, NTFS_NAME_LEN,
UTF16_HOST_ENDIAN);
if (err < 0)
goto out;

#ifdef CONFIG_NTFS3_FS_POSIX_ACL
if (IS_POSIXACL(dir)) {
/*
* Load in cache current acl to avoid ni_lock(dir):
* ntfs_create_inode -> ntfs_init_acl -> posix_acl_create ->
* ntfs_get_acl -> ntfs_get_acl_ex -> ni_lock
*/
struct posix_acl *p = get_inode_acl(dir, ACL_TYPE_DEFAULT);

if (IS_ERR(p)) {
err = PTR_ERR(p);
goto out;
}
posix_acl_release(p);
}
#endif

if (d_in_lookup(dentry)) {
ni_lock_dir(ni);
locked = true;
fnd = fnd_get();
if (!fnd) {
err = -ENOMEM;
goto out1;
}

d = d_splice_alias(dir_search_u(dir, uni, fnd), dentry);
if (IS_ERR(d)) {
err = PTR_ERR(d);
d = NULL;
goto out2;
}

if (d)
dentry = d;
}

if (!(flags & O_CREAT) || d_really_is_positive(dentry)) {
err = finish_no_open(file, d);
goto out2;
}

file->f_mode |= FMODE_CREATED;

/*
* fnd contains tree's path to insert to.
* If fnd is not NULL then dir is locked.
*/
inode = ntfs_create_inode(file_mnt_idmap(file), dir, dentry, uni,
mode, 0, NULL, 0, fnd);
err = IS_ERR(inode) ? PTR_ERR(inode) :
finish_open(file, dentry, ntfs_file_open);
dput(d);

out2:
fnd_put(fnd);
out1:
if (locked)
ni_unlock(ni);
out:
__putname(uni);
return err;
}

struct dentry *ntfs3_get_parent(struct dentry *child)
{
struct inode *inode = d_inode(child);
Expand Down Expand Up @@ -612,7 +508,6 @@ const struct inode_operations ntfs_dir_inode_operations = {
.setattr = ntfs3_setattr,
.getattr = ntfs_getattr,
.listxattr = ntfs_listxattr,
.atomic_open = ntfs_atomic_open,
.fiemap = ntfs_fiemap,
};

Expand Down
2 changes: 1 addition & 1 deletion fs/ntfs3/ntfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ struct GUID {
struct cpu_str {
u8 len;
u8 unused;
u16 name[10];
u16 name[];
};

struct le_str {
Expand Down
Loading

0 comments on commit 89b61ca

Please sign in to comment.