diff options
author | 2024-05-28 22:21:34 +0200 | |
---|---|---|
committer | 2024-05-28 22:21:34 +0200 | |
commit | f73a058be5d70dd81a43f16b2bbff4b1576a7af8 (patch) | |
tree | b7959c01cf7a5d95c7c4d5b61929ff9123370322 /fs/ntfs3 | |
parent | dma-buf: handle testing kthreads creation failure (diff) | |
parent | Merge tag 'drm-misc-fixes-2024-05-23' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-fixes (diff) | |
download | wireguard-linux-f73a058be5d70dd81a43f16b2bbff4b1576a7af8.tar.xz wireguard-linux-f73a058be5d70dd81a43f16b2bbff4b1576a7af8.zip |
Merge remote-tracking branch 'drm/drm-fixes' into drm-misc-fixes
v6.10-rc1 is released, forward from v6.9
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Diffstat (limited to 'fs/ntfs3')
-rw-r--r-- | fs/ntfs3/Kconfig | 9 | ||||
-rw-r--r-- | fs/ntfs3/attrib.c | 32 | ||||
-rw-r--r-- | fs/ntfs3/bitmap.c | 4 | ||||
-rw-r--r-- | fs/ntfs3/dir.c | 8 | ||||
-rw-r--r-- | fs/ntfs3/file.c | 17 | ||||
-rw-r--r-- | fs/ntfs3/frecord.c | 2 | ||||
-rw-r--r-- | fs/ntfs3/fslog.c | 5 | ||||
-rw-r--r-- | fs/ntfs3/fsntfs.c | 2 | ||||
-rw-r--r-- | fs/ntfs3/index.c | 17 | ||||
-rw-r--r-- | fs/ntfs3/inode.c | 66 | ||||
-rw-r--r-- | fs/ntfs3/namei.c | 121 | ||||
-rw-r--r-- | fs/ntfs3/ntfs.h | 2 | ||||
-rw-r--r-- | fs/ntfs3/ntfs_fs.h | 18 | ||||
-rw-r--r-- | fs/ntfs3/record.c | 11 | ||||
-rw-r--r-- | fs/ntfs3/super.c | 69 | ||||
-rw-r--r-- | fs/ntfs3/xattr.c | 5 |
16 files changed, 216 insertions, 172 deletions
diff --git a/fs/ntfs3/Kconfig b/fs/ntfs3/Kconfig index cdfdf51e55d7..7bc31d69f680 100644 --- a/fs/ntfs3/Kconfig +++ b/fs/ntfs3/Kconfig @@ -46,3 +46,12 @@ config NTFS3_FS_POSIX_ACL NOTE: this is linux only feature. Windows will ignore these ACLs. If you don't know what Access Control Lists are, say N. + +config NTFS_FS + tristate "NTFS file system support" + select NTFS3_FS + select BUFFER_HEAD + select NLS + help + This config option is here only for backward compatibility. NTFS + filesystem is now handled by the NTFS3 driver. diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index 7aadf5010999..8e6bcdf99770 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -2558,3 +2558,35 @@ undo_insert_range: 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; +} diff --git a/fs/ntfs3/bitmap.c b/fs/ntfs3/bitmap.c index 845f9b22deef..c9eb01ccee51 100644 --- a/fs/ntfs3/bitmap.c +++ b/fs/ntfs3/bitmap.c @@ -654,7 +654,7 @@ int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits) wnd->total_zeroes = nbits; wnd->extent_max = MINUS_ONE_T; wnd->zone_bit = wnd->zone_end = 0; - wnd->nwnd = bytes_to_block(sb, bitmap_size(nbits)); + wnd->nwnd = bytes_to_block(sb, ntfs3_bitmap_size(nbits)); wnd->bits_last = nbits & (wbits - 1); if (!wnd->bits_last) wnd->bits_last = wbits; @@ -1347,7 +1347,7 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits) return -EINVAL; /* Align to 8 byte boundary. */ - new_wnd = bytes_to_block(sb, bitmap_size(new_bits)); + new_wnd = bytes_to_block(sb, ntfs3_bitmap_size(new_bits)); new_last = new_bits & (wbits - 1); if (!new_last) new_last = wbits; diff --git a/fs/ntfs3/dir.c b/fs/ntfs3/dir.c index 5cf3d9decf64..1937e8e612f8 100644 --- a/fs/ntfs3/dir.c +++ b/fs/ntfs3/dir.c @@ -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; } @@ -616,4 +617,11 @@ const struct file_operations ntfs_dir_operations = { .compat_ioctl = ntfs_compat_ioctl, #endif }; + +const struct file_operations ntfs_legacy_dir_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .iterate_shared = ntfs_readdir, + .open = ntfs_file_open, +}; // clang-format on diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 5418662c80d8..2f903b6ce157 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -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); @@ -1236,4 +1245,12 @@ const struct file_operations ntfs_file_operations = { .fallocate = ntfs_fallocate, .release = ntfs_file_release, }; + +const struct file_operations ntfs_legacy_file_operations = { + .llseek = generic_file_llseek, + .read_iter = ntfs_file_read_iter, + .splice_read = ntfs_file_splice_read, + .open = ntfs_file_open, + .release = ntfs_file_release, +}; // clang-format on diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 7f27382e0ce2..0008670939a4 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -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; diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c index 855519713bf7..d7807d255dfe 100644 --- a/fs/ntfs3/fslog.c +++ b/fs/ntfs3/fslog.c @@ -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. */ @@ -1184,7 +1184,8 @@ out: 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. */ diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index ae2ef5c11868..626d3f2c7e2d 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -522,7 +522,7 @@ static int ntfs_extend_mft(struct ntfs_sb_info *sbi) ni->mi.dirty = true; /* Step 2: Resize $MFT::BITMAP. */ - new_bitmap_bytes = bitmap_size(new_mft_total); + new_bitmap_bytes = ntfs3_bitmap_size(new_mft_total); err = attr_set_size(ni, ATTR_BITMAP, NULL, 0, &sbi->mft.bitmap.run, new_bitmap_bytes, &new_bitmap_bytes, true, NULL); diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index daabaad63aaf..d0f15bbf78f6 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -1456,8 +1456,8 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, alloc->nres.valid_size = alloc->nres.data_size = cpu_to_le64(data_size); - err = ni_insert_resident(ni, bitmap_size(1), ATTR_BITMAP, in->name, - in->name_len, &bitmap, NULL, NULL); + err = ni_insert_resident(ni, ntfs3_bitmap_size(1), ATTR_BITMAP, + in->name, in->name_len, &bitmap, NULL, NULL); if (err) goto out2; @@ -1518,8 +1518,9 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, if (bmp) { /* Increase bitmap. */ err = attr_set_size(ni, ATTR_BITMAP, in->name, in->name_len, - &indx->bitmap_run, bitmap_size(bit + 1), - NULL, true, NULL); + &indx->bitmap_run, + ntfs3_bitmap_size(bit + 1), NULL, true, + NULL); if (err) goto out1; } @@ -1533,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, @@ -1546,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; @@ -2092,7 +2099,7 @@ static int indx_shrink(struct ntfs_index *indx, struct ntfs_inode *ni, if (in->name == I30_NAME) i_size_write(&ni->vfs_inode, new_data); - bpb = bitmap_size(bit); + bpb = ntfs3_bitmap_size(bit); if (bpb * 8 == nbits) return 0; diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index eb7a8c9fba01..0f1664db94ad 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -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 @@ -200,11 +200,12 @@ next_attr: 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)) @@ -429,7 +430,7 @@ end_enum: ni->mi.dirty = true; } - set_nlink(inode, names); + set_nlink(inode, links); if (S_ISDIR(mode)) { ni->std_fa |= FILE_ATTRIBUTE_DIRECTORY; @@ -440,7 +441,10 @@ end_enum: * Usually a hard links to directories are disabled. */ inode->i_op = &ntfs_dir_inode_operations; - inode->i_fop = &ntfs_dir_operations; + if (is_legacy_ntfs(inode->i_sb)) + inode->i_fop = &ntfs_legacy_dir_operations; + else + inode->i_fop = &ntfs_dir_operations; ni->i_valid = 0; } else if (S_ISLNK(mode)) { ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY; @@ -450,7 +454,10 @@ end_enum: } else if (S_ISREG(mode)) { ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY; inode->i_op = &ntfs_file_inode_operations; - inode->i_fop = &ntfs_file_operations; + if (is_legacy_ntfs(inode->i_sb)) + inode->i_fop = &ntfs_legacy_file_operations; + else + inode->i_fop = &ntfs_file_operations; inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr : &ntfs_aops; if (ino != MFT_REC_MFT) @@ -570,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; } @@ -1210,11 +1222,10 @@ out: * * 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; @@ -1239,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); @@ -1478,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. */ @@ -1614,7 +1628,10 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, if (S_ISDIR(mode)) { inode->i_op = &ntfs_dir_inode_operations; - inode->i_fop = &ntfs_dir_operations; + if (is_legacy_ntfs(inode->i_sb)) + inode->i_fop = &ntfs_legacy_dir_operations; + else + inode->i_fop = &ntfs_dir_operations; } else if (S_ISLNK(mode)) { inode->i_op = &ntfs_link_inode_operations; inode->i_fop = NULL; @@ -1623,7 +1640,10 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, inode_nohighmem(inode); } else if (S_ISREG(mode)) { inode->i_op = &ntfs_file_inode_operations; - inode->i_fop = &ntfs_file_operations; + if (is_legacy_ntfs(inode->i_sb)) + inode->i_fop = &ntfs_legacy_file_operations; + else + inode->i_fop = &ntfs_file_operations; inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr : &ntfs_aops; init_rwsem(&ni->file.run_lock); @@ -1715,12 +1735,10 @@ out1: 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) diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index 084d19d78397..71498421ce60 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -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); } /* @@ -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); } /* @@ -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); } /* @@ -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); } /* @@ -358,95 +343,6 @@ out: 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); @@ -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, }; diff --git a/fs/ntfs3/ntfs.h b/fs/ntfs3/ntfs.h index 9c7478150a03..3d6143c7abc0 100644 --- a/fs/ntfs3/ntfs.h +++ b/fs/ntfs3/ntfs.h @@ -59,7 +59,7 @@ struct GUID { struct cpu_str { u8 len; u8 unused; - u16 name[10]; + u16 name[]; }; struct le_str { diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 79356fd29a14..f9ed6d2b065d 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -452,6 +452,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size, 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); /* Functions from attrlist.c */ void al_destroy(struct ntfs_inode *ni); @@ -493,6 +494,7 @@ struct inode *dir_search_u(struct inode *dir, const struct cpu_str *uni, struct ntfs_fnd *fnd); bool dir_is_empty(struct inode *dir); extern const struct file_operations ntfs_dir_operations; +extern const struct file_operations ntfs_legacy_dir_operations; /* Globals from file.c */ int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path, @@ -507,6 +509,7 @@ long ntfs_compat_ioctl(struct file *filp, u32 cmd, unsigned long arg); extern const struct inode_operations ntfs_special_inode_operations; extern const struct inode_operations ntfs_file_inode_operations; extern const struct file_operations ntfs_file_operations; +extern const struct file_operations ntfs_legacy_file_operations; /* Globals from frecord.c */ void ni_remove_mi(struct ntfs_inode *ni, struct mft_inode *mi); @@ -714,11 +717,10 @@ int ntfs_sync_inode(struct inode *inode); int ntfs_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2); int inode_write_data(struct inode *inode, const void *data, size_t bytes); -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 ntfs_link_inode(struct inode *inode, struct dentry *dentry); int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry); void ntfs_evict_inode(struct inode *inode); @@ -966,9 +968,9 @@ static inline bool run_is_empty(struct runs_tree *run) } /* NTFS uses quad aligned bitmaps. */ -static inline size_t bitmap_size(size_t bits) +static inline size_t ntfs3_bitmap_size(size_t bits) { - return ALIGN((bits + 7) >> 3, 8); + return BITS_TO_U64(bits) * sizeof(u64); } #define _100ns2seconds 10000000 @@ -1154,4 +1156,6 @@ static inline void le64_sub_cpu(__le64 *var, u64 val) *var = cpu_to_le64(le64_to_cpu(*var) - val); } +bool is_legacy_ntfs(struct super_block *sb); + #endif /* _LINUX_NTFS3_NTFS_FS_H */ diff --git a/fs/ntfs3/record.c b/fs/ntfs3/record.c index 6aa3a9d44df1..6c76503edc20 100644 --- a/fs/ntfs3/record.c +++ b/fs/ntfs3/record.c @@ -534,16 +534,9 @@ bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi, if (aoff + asize > used) return false; - if (ni && is_attr_indexed(attr)) { + if (ni && is_attr_indexed(attr) && attr->type == ATTR_NAME) { u16 links = le16_to_cpu(ni->mi.mrec->hard_links); - struct ATTR_FILE_NAME *fname = - attr->type != ATTR_NAME ? - NULL : - resident_data_ex(attr, - SIZEOF_ATTRIBUTE_FILENAME); - if (fname && fname->type == FILE_NAME_DOS) { - /* Do not decrease links count deleting DOS name. */ - } else if (!links) { + if (!links) { /* minor error. Not critical. */ } else { ni->mi.mrec->hard_links = cpu_to_le16(links - 1); diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 9df7c20d066f..27fbde2701b6 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -408,6 +408,12 @@ static int ntfs_fs_reconfigure(struct fs_context *fc) struct ntfs_mount_options *new_opts = fc->fs_private; int ro_rw; + /* If ntfs3 is used as legacy ntfs enforce read-only mode. */ + if (is_legacy_ntfs(sb)) { + fc->sb_flags |= SB_RDONLY; + goto out; + } + ro_rw = sb_rdonly(sb) && !(fc->sb_flags & SB_RDONLY); if (ro_rw && (sbi->flags & NTFS_FLAGS_NEED_REPLAY)) { errorf(fc, @@ -427,8 +433,6 @@ static int ntfs_fs_reconfigure(struct fs_context *fc) fc, "ntfs3: Cannot use different iocharset when remounting!"); - sync_filesystem(sb); - if (ro_rw && (sbi->volume.flags & VOLUME_FLAG_DIRTY) && !new_opts->force) { errorf(fc, @@ -436,6 +440,8 @@ static int ntfs_fs_reconfigure(struct fs_context *fc) return -EINVAL; } +out: + sync_filesystem(sb); swap(sbi->options, fc->fs_private); return 0; @@ -1341,7 +1347,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) /* Check bitmap boundary. */ tt = sbi->used.bitmap.nbits; - if (inode->i_size < bitmap_size(tt)) { + if (inode->i_size < ntfs3_bitmap_size(tt)) { ntfs_err(sb, "$Bitmap is corrupted."); err = -EINVAL; goto put_inode_out; @@ -1613,6 +1619,8 @@ load_root: } #endif + if (is_legacy_ntfs(sb)) + sb->s_flags |= SB_RDONLY; return 0; put_inode_out: @@ -1730,7 +1738,7 @@ static const struct fs_context_operations ntfs_context_ops = { * This will called when mount/remount. We will first initialize * options so that if remount we can use just that. */ -static int ntfs_init_fs_context(struct fs_context *fc) +static int __ntfs_init_fs_context(struct fs_context *fc) { struct ntfs_mount_options *opts; struct ntfs_sb_info *sbi; @@ -1778,6 +1786,11 @@ free_opts: return -ENOMEM; } +static int ntfs_init_fs_context(struct fs_context *fc) +{ + return __ntfs_init_fs_context(fc); +} + static void ntfs3_kill_sb(struct super_block *sb) { struct ntfs_sb_info *sbi = sb->s_fs_info; @@ -1798,14 +1811,56 @@ static struct file_system_type ntfs_fs_type = { .kill_sb = ntfs3_kill_sb, .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP, }; + +#if IS_ENABLED(CONFIG_NTFS_FS) +static int ntfs_legacy_init_fs_context(struct fs_context *fc) +{ + int ret; + + ret = __ntfs_init_fs_context(fc); + /* If ntfs3 is used as legacy ntfs enforce read-only mode. */ + fc->sb_flags |= SB_RDONLY; + return ret; +} + +static struct file_system_type ntfs_legacy_fs_type = { + .owner = THIS_MODULE, + .name = "ntfs", + .init_fs_context = ntfs_legacy_init_fs_context, + .parameters = ntfs_fs_parameters, + .kill_sb = ntfs3_kill_sb, + .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP, +}; +MODULE_ALIAS_FS("ntfs"); + +static inline void register_as_ntfs_legacy(void) +{ + int err = register_filesystem(&ntfs_legacy_fs_type); + if (err) + pr_warn("ntfs3: Failed to register legacy ntfs filesystem driver: %d\n", err); +} + +static inline void unregister_as_ntfs_legacy(void) +{ + unregister_filesystem(&ntfs_legacy_fs_type); +} +bool is_legacy_ntfs(struct super_block *sb) +{ + return sb->s_type == &ntfs_legacy_fs_type; +} +#else +static inline void register_as_ntfs_legacy(void) {} +static inline void unregister_as_ntfs_legacy(void) {} +bool is_legacy_ntfs(struct super_block *sb) { return false; } +#endif + + // clang-format on static int __init init_ntfs_fs(void) { int err; - pr_info("ntfs3: Max link count %u\n", NTFS_LINK_MAX); - if (IS_ENABLED(CONFIG_NTFS3_FS_POSIX_ACL)) pr_info("ntfs3: Enabled Linux POSIX ACLs support\n"); if (IS_ENABLED(CONFIG_NTFS3_64BIT_CLUSTER)) @@ -1832,6 +1887,7 @@ static int __init init_ntfs_fs(void) goto out1; } + register_as_ntfs_legacy(); err = register_filesystem(&ntfs_fs_type); if (err) goto out; @@ -1849,6 +1905,7 @@ static void __exit exit_ntfs_fs(void) rcu_barrier(); kmem_cache_destroy(ntfs_inode_cachep); unregister_filesystem(&ntfs_fs_type); + unregister_as_ntfs_legacy(); ntfs3_exit_bitmap(); #ifdef CONFIG_PROC_FS diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 53e7d1fa036a..73785dece7a7 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -219,8 +219,11 @@ static ssize_t ntfs_list_ea(struct ntfs_inode *ni, char *buffer, if (!ea->name_len) break; - if (ea->name_len > ea_size) + if (ea->name_len > ea_size) { + ntfs_set_state(ni->mi.sbi, NTFS_DIRTY_ERROR); + err = -EINVAL; /* corrupted fs */ break; + } if (buffer) { /* Check if we can use field ea->name */ |