driver ntfs3 for linux 6.8
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEh0DEKNP0I9IjwfWEqbAzH4MkB7YFAmXGIMMACgkQqbAzH4Mk B7b07xAAw/VcHqPdhcVg2SttGy1D0rpjXvSK9Na3pulD83M3AptvjqXToP1xZHUP fpZ32rAWoeaJieTbS+xJUEyRj+VGN9iEgUMBtoaIYIv9ozmC7IU0xyDvJCPU07F1 X2n+IXxpBsU/Y1rQiJIijzum+BQYgXgsifdwkZU50QQjQWWcFdMU9VPjN2Saw/Sx 8gd1rzKVKIclErpReDyuZpTqDweM4BxiuwKhLodzlMtfO2MEqXxwFXnLQDX2xJLh zJPMepM/3mzHSBjKrHQ+xZHZCDuP393UUJK+sd9PaETR8xHR4ew9yqSu1Ajg/o64 xoQ8rkpT9g6AZS+JNKtKN52rw5rn4ZCi/VZ61HgqiLGTxOkVnHpynmDr3IKzfgn+ j7ZD33HteBJLxnR3YTi7fJA8DF9d0vHUv+HtH351WVibJn9DrzWzIkp6uDdaVfoa YvVE+ODynLVvpDKVTm4QOmIRnVMFDZwNo7C2sURy6nqQYf+ufYYRbe5btrvhSZ8k uazJLhLSLFCHiT6WlbmykntTo15sub/yIF5juVRcWthi2jWj0qII549jtSkZquQR pEVcitMTrr6RqwEB/B5nsz2azQ4m/+JgO0se1kWvxa+6erVV0wCdB7STW77zbRmx m8Xyr8Pf+ZxM+IhP4cpSxgcc5olhvUjcrkNBtilQc0vLqf535k0= =4Gkn -----END PGP SIGNATURE----- Merge tag 'ntfs3_for_6.8' of https://github.com/Paragon-Software-Group/linux-ntfs3 Pull ntfs3 fixes from Konstantin Komarov: "Fixed: - size update for compressed file - some logic errors, overflows - memory leak - some code was refactored Added: - implement super_operations::shutdown Improved: - alternative boot processing - reduced stack usage" * tag 'ntfs3_for_6.8' of https://github.com/Paragon-Software-Group/linux-ntfs3: (28 commits) fs/ntfs3: Slightly simplify ntfs_inode_printk() fs/ntfs3: Add ioctl operation for directories (FITRIM) fs/ntfs3: Fix oob in ntfs_listxattr fs/ntfs3: Fix an NULL dereference bug fs/ntfs3: Update inode->i_size after success write into compressed file fs/ntfs3: Fixed overflow check in mi_enum_attr() fs/ntfs3: Correct function is_rst_area_valid fs/ntfs3: Use i_size_read and i_size_write fs/ntfs3: Prevent generic message "attempt to access beyond end of device" fs/ntfs3: use non-movable memory for ntfs3 MFT buffer cache fs/ntfs3: Use kvfree to free memory allocated by kvmalloc fs/ntfs3: Disable ATTR_LIST_ENTRY size check fs/ntfs3: Fix c/mtime typo fs/ntfs3: Add NULL ptr dereference checking at the end of attr_allocate_frame() fs/ntfs3: Add and fix comments fs/ntfs3: ntfs3_forced_shutdown use int instead of bool fs/ntfs3: Implement super_operations::shutdown fs/ntfs3: Drop suid and sgid bits as a part of fpunch fs/ntfs3: Add file_modified fs/ntfs3: Correct use bh_read ...
This commit is contained in:
commit
a2343df3fb
@ -886,7 +886,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
|
||||
struct runs_tree *run = &ni->file.run;
|
||||
struct ntfs_sb_info *sbi;
|
||||
u8 cluster_bits;
|
||||
struct ATTRIB *attr = NULL, *attr_b;
|
||||
struct ATTRIB *attr, *attr_b;
|
||||
struct ATTR_LIST_ENTRY *le, *le_b;
|
||||
struct mft_inode *mi, *mi_b;
|
||||
CLST hint, svcn, to_alloc, evcn1, next_svcn, asize, end, vcn0, alen;
|
||||
@ -904,12 +904,8 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
|
||||
*len = 0;
|
||||
up_read(&ni->file.run_lock);
|
||||
|
||||
if (*len) {
|
||||
if (*lcn != SPARSE_LCN || !new)
|
||||
return 0; /* Fast normal way without allocation. */
|
||||
else if (clen > *len)
|
||||
clen = *len;
|
||||
}
|
||||
if (*len && (*lcn != SPARSE_LCN || !new))
|
||||
return 0; /* Fast normal way without allocation. */
|
||||
|
||||
/* No cluster in cache or we need to allocate cluster in hole. */
|
||||
sbi = ni->mi.sbi;
|
||||
@ -918,6 +914,17 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
|
||||
ni_lock(ni);
|
||||
down_write(&ni->file.run_lock);
|
||||
|
||||
/* Repeat the code above (under write lock). */
|
||||
if (!run_lookup_entry(run, vcn, lcn, len, NULL))
|
||||
*len = 0;
|
||||
|
||||
if (*len) {
|
||||
if (*lcn != SPARSE_LCN || !new)
|
||||
goto out; /* normal way without allocation. */
|
||||
if (clen > *len)
|
||||
clen = *len;
|
||||
}
|
||||
|
||||
le_b = NULL;
|
||||
attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
|
||||
if (!attr_b) {
|
||||
@ -1736,8 +1743,10 @@ repack:
|
||||
le_b = NULL;
|
||||
attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL,
|
||||
0, NULL, &mi_b);
|
||||
if (!attr_b)
|
||||
return -ENOENT;
|
||||
if (!attr_b) {
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
attr = attr_b;
|
||||
le = le_b;
|
||||
@ -1818,13 +1827,15 @@ ins_ext:
|
||||
ok:
|
||||
run_truncate_around(run, vcn);
|
||||
out:
|
||||
if (new_valid > data_size)
|
||||
new_valid = data_size;
|
||||
if (attr_b) {
|
||||
if (new_valid > data_size)
|
||||
new_valid = data_size;
|
||||
|
||||
valid_size = le64_to_cpu(attr_b->nres.valid_size);
|
||||
if (new_valid != valid_size) {
|
||||
attr_b->nres.valid_size = cpu_to_le64(valid_size);
|
||||
mi_b->dirty = true;
|
||||
valid_size = le64_to_cpu(attr_b->nres.valid_size);
|
||||
if (new_valid != valid_size) {
|
||||
attr_b->nres.valid_size = cpu_to_le64(valid_size);
|
||||
mi_b->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -2073,7 +2084,7 @@ next_attr:
|
||||
|
||||
/* Update inode size. */
|
||||
ni->i_valid = valid_size;
|
||||
ni->vfs_inode.i_size = data_size;
|
||||
i_size_write(&ni->vfs_inode, data_size);
|
||||
inode_set_bytes(&ni->vfs_inode, total_size);
|
||||
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
|
||||
mark_inode_dirty(&ni->vfs_inode);
|
||||
@ -2488,7 +2499,7 @@ int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
|
||||
mi_b->dirty = true;
|
||||
|
||||
done:
|
||||
ni->vfs_inode.i_size += bytes;
|
||||
i_size_write(&ni->vfs_inode, ni->vfs_inode.i_size + bytes);
|
||||
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
|
||||
mark_inode_dirty(&ni->vfs_inode);
|
||||
|
||||
|
@ -29,7 +29,7 @@ static inline bool al_is_valid_le(const struct ntfs_inode *ni,
|
||||
void al_destroy(struct ntfs_inode *ni)
|
||||
{
|
||||
run_close(&ni->attr_list.run);
|
||||
kfree(ni->attr_list.le);
|
||||
kvfree(ni->attr_list.le);
|
||||
ni->attr_list.le = NULL;
|
||||
ni->attr_list.size = 0;
|
||||
ni->attr_list.dirty = false;
|
||||
@ -127,12 +127,13 @@ struct ATTR_LIST_ENTRY *al_enumerate(struct ntfs_inode *ni,
|
||||
{
|
||||
size_t off;
|
||||
u16 sz;
|
||||
const unsigned le_min_size = le_size(0);
|
||||
|
||||
if (!le) {
|
||||
le = ni->attr_list.le;
|
||||
} else {
|
||||
sz = le16_to_cpu(le->size);
|
||||
if (sz < sizeof(struct ATTR_LIST_ENTRY)) {
|
||||
if (sz < le_min_size) {
|
||||
/* Impossible 'cause we should not return such le. */
|
||||
return NULL;
|
||||
}
|
||||
@ -141,7 +142,7 @@ struct ATTR_LIST_ENTRY *al_enumerate(struct ntfs_inode *ni,
|
||||
|
||||
/* Check boundary. */
|
||||
off = PtrOffset(ni->attr_list.le, le);
|
||||
if (off + sizeof(struct ATTR_LIST_ENTRY) > ni->attr_list.size) {
|
||||
if (off + le_min_size > ni->attr_list.size) {
|
||||
/* The regular end of list. */
|
||||
return NULL;
|
||||
}
|
||||
@ -149,8 +150,7 @@ struct ATTR_LIST_ENTRY *al_enumerate(struct ntfs_inode *ni,
|
||||
sz = le16_to_cpu(le->size);
|
||||
|
||||
/* Check le for errors. */
|
||||
if (sz < sizeof(struct ATTR_LIST_ENTRY) ||
|
||||
off + sz > ni->attr_list.size ||
|
||||
if (sz < le_min_size || off + sz > ni->attr_list.size ||
|
||||
sz < le->name_off + le->name_len * sizeof(short)) {
|
||||
return NULL;
|
||||
}
|
||||
@ -318,7 +318,7 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
|
||||
memcpy(ptr, al->le, off);
|
||||
memcpy(Add2Ptr(ptr, off + sz), le, old_size - off);
|
||||
le = Add2Ptr(ptr, off);
|
||||
kfree(al->le);
|
||||
kvfree(al->le);
|
||||
al->le = ptr;
|
||||
} else {
|
||||
memmove(Add2Ptr(le, sz), le, old_size - off);
|
||||
|
@ -124,7 +124,7 @@ void wnd_close(struct wnd_bitmap *wnd)
|
||||
{
|
||||
struct rb_node *node, *next;
|
||||
|
||||
kfree(wnd->free_bits);
|
||||
kvfree(wnd->free_bits);
|
||||
wnd->free_bits = NULL;
|
||||
run_close(&wnd->run);
|
||||
|
||||
@ -1360,7 +1360,7 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
|
||||
memcpy(new_free, wnd->free_bits, wnd->nwnd * sizeof(short));
|
||||
memset(new_free + wnd->nwnd, 0,
|
||||
(new_wnd - wnd->nwnd) * sizeof(short));
|
||||
kfree(wnd->free_bits);
|
||||
kvfree(wnd->free_bits);
|
||||
wnd->free_bits = new_free;
|
||||
}
|
||||
|
||||
|
@ -309,11 +309,31 @@ static inline int ntfs_filldir(struct ntfs_sb_info *sbi, struct ntfs_inode *ni,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NTFS: symlinks are "dir + reparse" or "file + reparse" */
|
||||
if (fname->dup.fa & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
dt_type = DT_LNK;
|
||||
else
|
||||
dt_type = (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
|
||||
/*
|
||||
* NTFS: symlinks are "dir + reparse" or "file + reparse"
|
||||
* Unfortunately reparse attribute is used for many purposes (several dozens).
|
||||
* It is not possible here to know is this name symlink or not.
|
||||
* To get exactly the type of name we should to open inode (read mft).
|
||||
* getattr for opened file (fstat) correctly returns symlink.
|
||||
*/
|
||||
dt_type = (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
|
||||
|
||||
/*
|
||||
* It is not reliable to detect the type of name using duplicated information
|
||||
* stored in parent directory.
|
||||
* The only correct way to get the type of name - read MFT record and find ATTR_STD.
|
||||
* The code below is not good idea.
|
||||
* It does additional locks/reads just to get the type of name.
|
||||
* Should we use additional mount option to enable branch below?
|
||||
*/
|
||||
if ((fname->dup.fa & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||
ino != ni->mi.rno) {
|
||||
struct inode *inode = ntfs_iget5(sbi->sb, &e->ref, NULL);
|
||||
if (!IS_ERR_OR_NULL(inode)) {
|
||||
dt_type = fs_umode_to_dtype(inode->i_mode);
|
||||
iput(inode);
|
||||
}
|
||||
}
|
||||
|
||||
return !dir_emit(ctx, (s8 *)name, name_len, ino, dt_type);
|
||||
}
|
||||
@ -495,11 +515,9 @@ static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
|
||||
struct INDEX_HDR *hdr;
|
||||
const struct ATTR_FILE_NAME *fname;
|
||||
u32 e_size, off, end;
|
||||
u64 vbo = 0;
|
||||
size_t drs = 0, fles = 0, bit = 0;
|
||||
loff_t i_size = ni->vfs_inode.i_size;
|
||||
struct indx_node *node = NULL;
|
||||
u8 index_bits = ni->dir.index_bits;
|
||||
size_t max_indx = i_size_read(&ni->vfs_inode) >> ni->dir.index_bits;
|
||||
|
||||
if (is_empty)
|
||||
*is_empty = true;
|
||||
@ -518,8 +536,10 @@ static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
|
||||
e = Add2Ptr(hdr, off);
|
||||
e_size = le16_to_cpu(e->size);
|
||||
if (e_size < sizeof(struct NTFS_DE) ||
|
||||
off + e_size > end)
|
||||
off + e_size > end) {
|
||||
/* Looks like corruption. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (de_is_last(e))
|
||||
break;
|
||||
@ -543,7 +563,7 @@ static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
|
||||
fles += 1;
|
||||
}
|
||||
|
||||
if (vbo >= i_size)
|
||||
if (bit >= max_indx)
|
||||
goto out;
|
||||
|
||||
err = indx_used_bit(&ni->dir, ni, &bit);
|
||||
@ -553,8 +573,7 @@ static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
|
||||
if (bit == MINUS_ONE_T)
|
||||
goto out;
|
||||
|
||||
vbo = (u64)bit << index_bits;
|
||||
if (vbo >= i_size)
|
||||
if (bit >= max_indx)
|
||||
goto out;
|
||||
|
||||
err = indx_read(&ni->dir, ni, bit << ni->dir.idx2vbn_bits,
|
||||
@ -564,7 +583,6 @@ static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
|
||||
|
||||
hdr = &node->index->ihdr;
|
||||
bit += 1;
|
||||
vbo = (u64)bit << ni->dir.idx2vbn_bits;
|
||||
}
|
||||
|
||||
out:
|
||||
@ -593,5 +611,9 @@ const struct file_operations ntfs_dir_operations = {
|
||||
.iterate_shared = ntfs_readdir,
|
||||
.fsync = generic_file_fsync,
|
||||
.open = ntfs_file_open,
|
||||
.unlocked_ioctl = ntfs_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ntfs_compat_ioctl,
|
||||
#endif
|
||||
};
|
||||
// clang-format on
|
||||
|
@ -48,7 +48,7 @@ static int ntfs_ioctl_fitrim(struct ntfs_sb_info *sbi, unsigned long arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long ntfs_ioctl(struct file *filp, u32 cmd, unsigned long arg)
|
||||
long ntfs_ioctl(struct file *filp, u32 cmd, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
|
||||
@ -61,7 +61,7 @@ static long ntfs_ioctl(struct file *filp, u32 cmd, unsigned long arg)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static long ntfs_compat_ioctl(struct file *filp, u32 cmd, unsigned long arg)
|
||||
long ntfs_compat_ioctl(struct file *filp, u32 cmd, unsigned long arg)
|
||||
|
||||
{
|
||||
return ntfs_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
|
||||
@ -188,6 +188,7 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to)
|
||||
u32 bh_next, bh_off, to;
|
||||
sector_t iblock;
|
||||
struct folio *folio;
|
||||
bool dirty = false;
|
||||
|
||||
for (; idx < idx_end; idx += 1, from = 0) {
|
||||
page_off = (loff_t)idx << PAGE_SHIFT;
|
||||
@ -223,29 +224,27 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to)
|
||||
/* Ok, it's mapped. Make sure it's up-to-date. */
|
||||
if (folio_test_uptodate(folio))
|
||||
set_buffer_uptodate(bh);
|
||||
|
||||
if (!buffer_uptodate(bh)) {
|
||||
err = bh_read(bh, 0);
|
||||
if (err < 0) {
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
goto out;
|
||||
}
|
||||
else if (bh_read(bh, 0) < 0) {
|
||||
err = -EIO;
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mark_buffer_dirty(bh);
|
||||
|
||||
} while (bh_off = bh_next, iblock += 1,
|
||||
head != (bh = bh->b_this_page));
|
||||
|
||||
folio_zero_segment(folio, from, to);
|
||||
dirty = true;
|
||||
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
cond_resched();
|
||||
}
|
||||
out:
|
||||
mark_inode_dirty(inode);
|
||||
if (dirty)
|
||||
mark_inode_dirty(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -261,6 +260,9 @@ static int ntfs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
bool rw = vma->vm_flags & VM_WRITE;
|
||||
int err;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
if (is_encrypted(ni)) {
|
||||
ntfs_inode_warn(inode, "mmap encrypted not supported");
|
||||
return -EOPNOTSUPP;
|
||||
@ -499,10 +501,14 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
|
||||
ni_lock(ni);
|
||||
err = attr_punch_hole(ni, vbo, len, &frame_size);
|
||||
ni_unlock(ni);
|
||||
if (!err)
|
||||
goto ok;
|
||||
|
||||
if (err != E_NTFS_NOTALIGNED)
|
||||
goto out;
|
||||
|
||||
/* Process not aligned punch. */
|
||||
err = 0;
|
||||
mask = frame_size - 1;
|
||||
vbo_a = (vbo + mask) & ~mask;
|
||||
end_a = end & ~mask;
|
||||
@ -525,6 +531,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
|
||||
ni_lock(ni);
|
||||
err = attr_punch_hole(ni, vbo_a, end_a - vbo_a, NULL);
|
||||
ni_unlock(ni);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
|
||||
/*
|
||||
@ -564,6 +572,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
|
||||
ni_lock(ni);
|
||||
err = attr_insert_range(ni, vbo, len);
|
||||
ni_unlock(ni);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
/* Check new size. */
|
||||
u8 cluster_bits = sbi->cluster_bits;
|
||||
@ -633,11 +643,18 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
|
||||
&ni->file.run, i_size, &ni->i_valid,
|
||||
true, NULL);
|
||||
ni_unlock(ni);
|
||||
if (err)
|
||||
goto out;
|
||||
} else if (new_size > i_size) {
|
||||
inode->i_size = new_size;
|
||||
i_size_write(inode, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
ok:
|
||||
err = file_modified(file);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (map_locked)
|
||||
filemap_invalidate_unlock(mapping);
|
||||
@ -663,6 +680,9 @@ int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
umode_t mode = inode->i_mode;
|
||||
int err;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
err = setattr_prepare(idmap, dentry, attr);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -676,7 +696,7 @@ int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
goto out;
|
||||
}
|
||||
inode_dio_wait(inode);
|
||||
oldsize = inode->i_size;
|
||||
oldsize = i_size_read(inode);
|
||||
newsize = attr->ia_size;
|
||||
|
||||
if (newsize <= oldsize)
|
||||
@ -688,7 +708,7 @@ int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
goto out;
|
||||
|
||||
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
|
||||
inode->i_size = newsize;
|
||||
i_size_write(inode, newsize);
|
||||
}
|
||||
|
||||
setattr_copy(idmap, inode, attr);
|
||||
@ -718,6 +738,9 @@ static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
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;
|
||||
@ -752,6 +775,9 @@ static ssize_t ntfs_file_splice_read(struct file *in, loff_t *ppos,
|
||||
struct inode *inode = in->f_mapping->host;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
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;
|
||||
@ -821,7 +847,7 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
size_t count = iov_iter_count(from);
|
||||
loff_t pos = iocb->ki_pos;
|
||||
struct inode *inode = file_inode(file);
|
||||
loff_t i_size = inode->i_size;
|
||||
loff_t i_size = i_size_read(inode);
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
u64 valid = ni->i_valid;
|
||||
@ -1028,6 +1054,8 @@ out:
|
||||
iocb->ki_pos += written;
|
||||
if (iocb->ki_pos > ni->i_valid)
|
||||
ni->i_valid = iocb->ki_pos;
|
||||
if (iocb->ki_pos > i_size)
|
||||
i_size_write(inode, iocb->ki_pos);
|
||||
|
||||
return written;
|
||||
}
|
||||
@ -1041,8 +1069,12 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
struct inode *inode = mapping->host;
|
||||
ssize_t ret;
|
||||
int err;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
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;
|
||||
@ -1068,6 +1100,12 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
|
||||
err = file_modified(iocb->ki_filp);
|
||||
if (err) {
|
||||
ret = err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (WARN_ON(ni->ni_flags & NI_FLAG_COMPRESSED_MASK)) {
|
||||
/* Should never be here, see ntfs_file_open(). */
|
||||
ret = -EOPNOTSUPP;
|
||||
@ -1097,6 +1135,9 @@ int ntfs_file_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
if (unlikely((is_compressed(ni) || is_encrypted(ni)) &&
|
||||
(file->f_flags & O_DIRECT))) {
|
||||
return -EOPNOTSUPP;
|
||||
@ -1138,7 +1179,8 @@ static int ntfs_file_release(struct inode *inode, struct file *file)
|
||||
down_write(&ni->file.run_lock);
|
||||
|
||||
err = attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run,
|
||||
inode->i_size, &ni->i_valid, false, NULL);
|
||||
i_size_read(inode), &ni->i_valid, false,
|
||||
NULL);
|
||||
|
||||
up_write(&ni->file.run_lock);
|
||||
ni_unlock(ni);
|
||||
|
@ -778,7 +778,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
|
||||
run_deallocate(sbi, &ni->attr_list.run, true);
|
||||
run_close(&ni->attr_list.run);
|
||||
ni->attr_list.size = 0;
|
||||
kfree(ni->attr_list.le);
|
||||
kvfree(ni->attr_list.le);
|
||||
ni->attr_list.le = NULL;
|
||||
ni->attr_list.dirty = false;
|
||||
|
||||
@ -927,7 +927,7 @@ int ni_create_attr_list(struct ntfs_inode *ni)
|
||||
return 0;
|
||||
|
||||
out:
|
||||
kfree(ni->attr_list.le);
|
||||
kvfree(ni->attr_list.le);
|
||||
ni->attr_list.le = NULL;
|
||||
ni->attr_list.size = 0;
|
||||
return err;
|
||||
@ -2099,7 +2099,7 @@ int ni_readpage_cmpr(struct ntfs_inode *ni, struct page *page)
|
||||
gfp_t gfp_mask;
|
||||
struct page *pg;
|
||||
|
||||
if (vbo >= ni->vfs_inode.i_size) {
|
||||
if (vbo >= i_size_read(&ni->vfs_inode)) {
|
||||
SetPageUptodate(page);
|
||||
err = 0;
|
||||
goto out;
|
||||
@ -2173,7 +2173,7 @@ int ni_decompress_file(struct ntfs_inode *ni)
|
||||
{
|
||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||
struct inode *inode = &ni->vfs_inode;
|
||||
loff_t i_size = inode->i_size;
|
||||
loff_t i_size = i_size_read(inode);
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
gfp_t gfp_mask = mapping_gfp_mask(mapping);
|
||||
struct page **pages = NULL;
|
||||
@ -2457,6 +2457,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
|
||||
struct ATTR_LIST_ENTRY *le = NULL;
|
||||
struct runs_tree *run = &ni->file.run;
|
||||
u64 valid_size = ni->i_valid;
|
||||
loff_t i_size = i_size_read(&ni->vfs_inode);
|
||||
u64 vbo_disk;
|
||||
size_t unc_size;
|
||||
u32 frame_size, i, npages_disk, ondisk_size;
|
||||
@ -2548,7 +2549,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
|
||||
}
|
||||
}
|
||||
|
||||
frames = (ni->vfs_inode.i_size - 1) >> frame_bits;
|
||||
frames = (i_size - 1) >> frame_bits;
|
||||
|
||||
err = attr_wof_frame_info(ni, attr, run, frame64, frames,
|
||||
frame_bits, &ondisk_size, &vbo_data);
|
||||
@ -2556,8 +2557,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
|
||||
goto out2;
|
||||
|
||||
if (frame64 == frames) {
|
||||
unc_size = 1 + ((ni->vfs_inode.i_size - 1) &
|
||||
(frame_size - 1));
|
||||
unc_size = 1 + ((i_size - 1) & (frame_size - 1));
|
||||
ondisk_size = attr_size(attr) - vbo_data;
|
||||
} else {
|
||||
unc_size = frame_size;
|
||||
@ -3259,6 +3259,9 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
|
||||
if (is_bad_inode(inode) || sb_rdonly(sb))
|
||||
return 0;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(sb)))
|
||||
return -EIO;
|
||||
|
||||
if (!ni_trylock(ni)) {
|
||||
/* 'ni' is under modification, skip for now. */
|
||||
mark_inode_dirty_sync(inode);
|
||||
@ -3288,7 +3291,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
|
||||
modified = true;
|
||||
}
|
||||
|
||||
ts = inode_get_mtime(inode);
|
||||
ts = inode_get_ctime(inode);
|
||||
dup.c_time = kernel2nt(&ts);
|
||||
if (std->c_time != dup.c_time) {
|
||||
std->c_time = dup.c_time;
|
||||
|
228
fs/ntfs3/fslog.c
228
fs/ntfs3/fslog.c
@ -465,7 +465,7 @@ static inline bool is_rst_area_valid(const struct RESTART_HDR *rhdr)
|
||||
{
|
||||
const struct RESTART_AREA *ra;
|
||||
u16 cl, fl, ul;
|
||||
u32 off, l_size, file_dat_bits, file_size_round;
|
||||
u32 off, l_size, seq_bits;
|
||||
u16 ro = le16_to_cpu(rhdr->ra_off);
|
||||
u32 sys_page = le32_to_cpu(rhdr->sys_page_size);
|
||||
|
||||
@ -511,13 +511,15 @@ static inline bool is_rst_area_valid(const struct RESTART_HDR *rhdr)
|
||||
/* Make sure the sequence number bits match the log file size. */
|
||||
l_size = le64_to_cpu(ra->l_size);
|
||||
|
||||
file_dat_bits = sizeof(u64) * 8 - le32_to_cpu(ra->seq_num_bits);
|
||||
file_size_round = 1u << (file_dat_bits + 3);
|
||||
if (file_size_round != l_size &&
|
||||
(file_size_round < l_size || (file_size_round / 2) > l_size)) {
|
||||
return false;
|
||||
seq_bits = sizeof(u64) * 8 + 3;
|
||||
while (l_size) {
|
||||
l_size >>= 1;
|
||||
seq_bits -= 1;
|
||||
}
|
||||
|
||||
if (seq_bits != ra->seq_num_bits)
|
||||
return false;
|
||||
|
||||
/* The log page data offset and record header length must be quad-aligned. */
|
||||
if (!IS_ALIGNED(le16_to_cpu(ra->data_off), 8) ||
|
||||
!IS_ALIGNED(le16_to_cpu(ra->rec_hdr_len), 8))
|
||||
@ -974,6 +976,16 @@ skip_looking:
|
||||
return e;
|
||||
}
|
||||
|
||||
struct restart_info {
|
||||
u64 last_lsn;
|
||||
struct RESTART_HDR *r_page;
|
||||
u32 vbo;
|
||||
bool chkdsk_was_run;
|
||||
bool valid_page;
|
||||
bool initialized;
|
||||
bool restart;
|
||||
};
|
||||
|
||||
#define RESTART_SINGLE_PAGE_IO cpu_to_le16(0x0001)
|
||||
|
||||
#define NTFSLOG_WRAPPED 0x00000001
|
||||
@ -987,6 +999,7 @@ struct ntfs_log {
|
||||
struct ntfs_inode *ni;
|
||||
|
||||
u32 l_size;
|
||||
u32 orig_file_size;
|
||||
u32 sys_page_size;
|
||||
u32 sys_page_mask;
|
||||
u32 page_size;
|
||||
@ -1040,6 +1053,8 @@ struct ntfs_log {
|
||||
|
||||
struct CLIENT_ID client_id;
|
||||
u32 client_undo_commit;
|
||||
|
||||
struct restart_info rst_info, rst_info2;
|
||||
};
|
||||
|
||||
static inline u32 lsn_to_vbo(struct ntfs_log *log, const u64 lsn)
|
||||
@ -1105,16 +1120,6 @@ static inline bool verify_client_lsn(struct ntfs_log *log,
|
||||
lsn <= le64_to_cpu(log->ra->current_lsn) && lsn;
|
||||
}
|
||||
|
||||
struct restart_info {
|
||||
u64 last_lsn;
|
||||
struct RESTART_HDR *r_page;
|
||||
u32 vbo;
|
||||
bool chkdsk_was_run;
|
||||
bool valid_page;
|
||||
bool initialized;
|
||||
bool restart;
|
||||
};
|
||||
|
||||
static int read_log_page(struct ntfs_log *log, u32 vbo,
|
||||
struct RECORD_PAGE_HDR **buffer, bool *usa_error)
|
||||
{
|
||||
@ -1176,7 +1181,7 @@ out:
|
||||
* restart page header. It will stop the first time we find a
|
||||
* valid page header.
|
||||
*/
|
||||
static int log_read_rst(struct ntfs_log *log, u32 l_size, bool first,
|
||||
static int log_read_rst(struct ntfs_log *log, bool first,
|
||||
struct restart_info *info)
|
||||
{
|
||||
u32 skip, vbo;
|
||||
@ -1192,7 +1197,7 @@ static int log_read_rst(struct ntfs_log *log, u32 l_size, bool first,
|
||||
}
|
||||
|
||||
/* Loop continuously until we succeed. */
|
||||
for (; vbo < l_size; vbo = 2 * vbo + skip, skip = 0) {
|
||||
for (; vbo < log->l_size; vbo = 2 * vbo + skip, skip = 0) {
|
||||
bool usa_error;
|
||||
bool brst, bchk;
|
||||
struct RESTART_AREA *ra;
|
||||
@ -1285,22 +1290,17 @@ check_result:
|
||||
/*
|
||||
* Ilog_init_pg_hdr - Init @log from restart page header.
|
||||
*/
|
||||
static void log_init_pg_hdr(struct ntfs_log *log, u32 sys_page_size,
|
||||
u32 page_size, u16 major_ver, u16 minor_ver)
|
||||
static void log_init_pg_hdr(struct ntfs_log *log, u16 major_ver, u16 minor_ver)
|
||||
{
|
||||
log->sys_page_size = sys_page_size;
|
||||
log->sys_page_mask = sys_page_size - 1;
|
||||
log->page_size = page_size;
|
||||
log->page_mask = page_size - 1;
|
||||
log->page_bits = blksize_bits(page_size);
|
||||
log->sys_page_size = log->page_size;
|
||||
log->sys_page_mask = log->page_mask;
|
||||
|
||||
log->clst_per_page = log->page_size >> log->ni->mi.sbi->cluster_bits;
|
||||
if (!log->clst_per_page)
|
||||
log->clst_per_page = 1;
|
||||
|
||||
log->first_page = major_ver >= 2 ?
|
||||
0x22 * page_size :
|
||||
((sys_page_size << 1) + (page_size << 1));
|
||||
log->first_page = major_ver >= 2 ? 0x22 * log->page_size :
|
||||
4 * log->page_size;
|
||||
log->major_ver = major_ver;
|
||||
log->minor_ver = minor_ver;
|
||||
}
|
||||
@ -1308,12 +1308,11 @@ static void log_init_pg_hdr(struct ntfs_log *log, u32 sys_page_size,
|
||||
/*
|
||||
* log_create - Init @log in cases when we don't have a restart area to use.
|
||||
*/
|
||||
static void log_create(struct ntfs_log *log, u32 l_size, const u64 last_lsn,
|
||||
static void log_create(struct ntfs_log *log, const u64 last_lsn,
|
||||
u32 open_log_count, bool wrapped, bool use_multi_page)
|
||||
{
|
||||
log->l_size = l_size;
|
||||
/* All file offsets must be quadword aligned. */
|
||||
log->file_data_bits = blksize_bits(l_size) - 3;
|
||||
log->file_data_bits = blksize_bits(log->l_size) - 3;
|
||||
log->seq_num_mask = (8 << log->file_data_bits) - 1;
|
||||
log->seq_num_bits = sizeof(u64) * 8 - log->file_data_bits;
|
||||
log->seq_num = (last_lsn >> log->file_data_bits) + 2;
|
||||
@ -3720,10 +3719,8 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
|
||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||
struct ntfs_log *log;
|
||||
|
||||
struct restart_info rst_info, rst_info2;
|
||||
u64 rec_lsn, ra_lsn, checkpt_lsn = 0, rlsn = 0;
|
||||
u64 rec_lsn, checkpt_lsn = 0, rlsn = 0;
|
||||
struct ATTR_NAME_ENTRY *attr_names = NULL;
|
||||
struct ATTR_NAME_ENTRY *ane;
|
||||
struct RESTART_TABLE *dptbl = NULL;
|
||||
struct RESTART_TABLE *trtbl = NULL;
|
||||
const struct RESTART_TABLE *rt;
|
||||
@ -3741,9 +3738,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
|
||||
struct TRANSACTION_ENTRY *tr;
|
||||
struct DIR_PAGE_ENTRY *dp;
|
||||
u32 i, bytes_per_attr_entry;
|
||||
u32 l_size = ni->vfs_inode.i_size;
|
||||
u32 orig_file_size = l_size;
|
||||
u32 page_size, vbo, tail, off, dlen;
|
||||
u32 vbo, tail, off, dlen;
|
||||
u32 saved_len, rec_len, transact_id;
|
||||
bool use_second_page;
|
||||
struct RESTART_AREA *ra2, *ra = NULL;
|
||||
@ -3758,52 +3753,50 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
|
||||
u16 t16;
|
||||
u32 t32;
|
||||
|
||||
/* Get the size of page. NOTE: To replay we can use default page. */
|
||||
#if PAGE_SIZE >= DefaultLogPageSize && PAGE_SIZE <= DefaultLogPageSize * 2
|
||||
page_size = norm_file_page(PAGE_SIZE, &l_size, true);
|
||||
#else
|
||||
page_size = norm_file_page(PAGE_SIZE, &l_size, false);
|
||||
#endif
|
||||
if (!page_size)
|
||||
return -EINVAL;
|
||||
|
||||
log = kzalloc(sizeof(struct ntfs_log), GFP_NOFS);
|
||||
if (!log)
|
||||
return -ENOMEM;
|
||||
|
||||
log->ni = ni;
|
||||
log->l_size = l_size;
|
||||
log->one_page_buf = kmalloc(page_size, GFP_NOFS);
|
||||
log->l_size = log->orig_file_size = ni->vfs_inode.i_size;
|
||||
|
||||
/* Get the size of page. NOTE: To replay we can use default page. */
|
||||
#if PAGE_SIZE >= DefaultLogPageSize && PAGE_SIZE <= DefaultLogPageSize * 2
|
||||
log->page_size = norm_file_page(PAGE_SIZE, &log->l_size, true);
|
||||
#else
|
||||
log->page_size = norm_file_page(PAGE_SIZE, &log->l_size, false);
|
||||
#endif
|
||||
if (!log->page_size) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
log->one_page_buf = kmalloc(log->page_size, GFP_NOFS);
|
||||
if (!log->one_page_buf) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
log->page_size = page_size;
|
||||
log->page_mask = page_size - 1;
|
||||
log->page_bits = blksize_bits(page_size);
|
||||
log->page_mask = log->page_size - 1;
|
||||
log->page_bits = blksize_bits(log->page_size);
|
||||
|
||||
/* Look for a restart area on the disk. */
|
||||
memset(&rst_info, 0, sizeof(struct restart_info));
|
||||
err = log_read_rst(log, l_size, true, &rst_info);
|
||||
err = log_read_rst(log, true, &log->rst_info);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* remember 'initialized' */
|
||||
*initialized = rst_info.initialized;
|
||||
*initialized = log->rst_info.initialized;
|
||||
|
||||
if (!rst_info.restart) {
|
||||
if (rst_info.initialized) {
|
||||
if (!log->rst_info.restart) {
|
||||
if (log->rst_info.initialized) {
|
||||
/* No restart area but the file is not initialized. */
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_init_pg_hdr(log, page_size, page_size, 1, 1);
|
||||
log_create(log, l_size, 0, get_random_u32(), false, false);
|
||||
|
||||
log->ra = ra;
|
||||
log_init_pg_hdr(log, 1, 1);
|
||||
log_create(log, 0, get_random_u32(), false, false);
|
||||
|
||||
ra = log_create_ra(log);
|
||||
if (!ra) {
|
||||
@ -3820,25 +3813,26 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
|
||||
* If the restart offset above wasn't zero then we won't
|
||||
* look for a second restart.
|
||||
*/
|
||||
if (rst_info.vbo)
|
||||
if (log->rst_info.vbo)
|
||||
goto check_restart_area;
|
||||
|
||||
memset(&rst_info2, 0, sizeof(struct restart_info));
|
||||
err = log_read_rst(log, l_size, false, &rst_info2);
|
||||
err = log_read_rst(log, false, &log->rst_info2);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Determine which restart area to use. */
|
||||
if (!rst_info2.restart || rst_info2.last_lsn <= rst_info.last_lsn)
|
||||
if (!log->rst_info2.restart ||
|
||||
log->rst_info2.last_lsn <= log->rst_info.last_lsn)
|
||||
goto use_first_page;
|
||||
|
||||
use_second_page = true;
|
||||
|
||||
if (rst_info.chkdsk_was_run && page_size != rst_info.vbo) {
|
||||
if (log->rst_info.chkdsk_was_run &&
|
||||
log->page_size != log->rst_info.vbo) {
|
||||
struct RECORD_PAGE_HDR *sp = NULL;
|
||||
bool usa_error;
|
||||
|
||||
if (!read_log_page(log, page_size, &sp, &usa_error) &&
|
||||
if (!read_log_page(log, log->page_size, &sp, &usa_error) &&
|
||||
sp->rhdr.sign == NTFS_CHKD_SIGNATURE) {
|
||||
use_second_page = false;
|
||||
}
|
||||
@ -3846,52 +3840,43 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
|
||||
}
|
||||
|
||||
if (use_second_page) {
|
||||
kfree(rst_info.r_page);
|
||||
memcpy(&rst_info, &rst_info2, sizeof(struct restart_info));
|
||||
rst_info2.r_page = NULL;
|
||||
kfree(log->rst_info.r_page);
|
||||
memcpy(&log->rst_info, &log->rst_info2,
|
||||
sizeof(struct restart_info));
|
||||
log->rst_info2.r_page = NULL;
|
||||
}
|
||||
|
||||
use_first_page:
|
||||
kfree(rst_info2.r_page);
|
||||
kfree(log->rst_info2.r_page);
|
||||
|
||||
check_restart_area:
|
||||
/*
|
||||
* If the restart area is at offset 0, we want
|
||||
* to write the second restart area first.
|
||||
*/
|
||||
log->init_ra = !!rst_info.vbo;
|
||||
log->init_ra = !!log->rst_info.vbo;
|
||||
|
||||
/* If we have a valid page then grab a pointer to the restart area. */
|
||||
ra2 = rst_info.valid_page ?
|
||||
Add2Ptr(rst_info.r_page,
|
||||
le16_to_cpu(rst_info.r_page->ra_off)) :
|
||||
ra2 = log->rst_info.valid_page ?
|
||||
Add2Ptr(log->rst_info.r_page,
|
||||
le16_to_cpu(log->rst_info.r_page->ra_off)) :
|
||||
NULL;
|
||||
|
||||
if (rst_info.chkdsk_was_run ||
|
||||
if (log->rst_info.chkdsk_was_run ||
|
||||
(ra2 && ra2->client_idx[1] == LFS_NO_CLIENT_LE)) {
|
||||
bool wrapped = false;
|
||||
bool use_multi_page = false;
|
||||
u32 open_log_count;
|
||||
|
||||
/* Do some checks based on whether we have a valid log page. */
|
||||
if (!rst_info.valid_page) {
|
||||
open_log_count = get_random_u32();
|
||||
goto init_log_instance;
|
||||
}
|
||||
open_log_count = le32_to_cpu(ra2->open_log_count);
|
||||
open_log_count = log->rst_info.valid_page ?
|
||||
le32_to_cpu(ra2->open_log_count) :
|
||||
get_random_u32();
|
||||
|
||||
/*
|
||||
* If the restart page size isn't changing then we want to
|
||||
* check how much work we need to do.
|
||||
*/
|
||||
if (page_size != le32_to_cpu(rst_info.r_page->sys_page_size))
|
||||
goto init_log_instance;
|
||||
log_init_pg_hdr(log, 1, 1);
|
||||
|
||||
init_log_instance:
|
||||
log_init_pg_hdr(log, page_size, page_size, 1, 1);
|
||||
|
||||
log_create(log, l_size, rst_info.last_lsn, open_log_count,
|
||||
wrapped, use_multi_page);
|
||||
log_create(log, log->rst_info.last_lsn, open_log_count, wrapped,
|
||||
use_multi_page);
|
||||
|
||||
ra = log_create_ra(log);
|
||||
if (!ra) {
|
||||
@ -3916,28 +3901,27 @@ init_log_instance:
|
||||
* use the log file. We must use the system page size instead of the
|
||||
* default size if there is not a clean shutdown.
|
||||
*/
|
||||
t32 = le32_to_cpu(rst_info.r_page->sys_page_size);
|
||||
if (page_size != t32) {
|
||||
l_size = orig_file_size;
|
||||
page_size =
|
||||
norm_file_page(t32, &l_size, t32 == DefaultLogPageSize);
|
||||
t32 = le32_to_cpu(log->rst_info.r_page->sys_page_size);
|
||||
if (log->page_size != t32) {
|
||||
log->l_size = log->orig_file_size;
|
||||
log->page_size = norm_file_page(t32, &log->l_size,
|
||||
t32 == DefaultLogPageSize);
|
||||
}
|
||||
|
||||
if (page_size != t32 ||
|
||||
page_size != le32_to_cpu(rst_info.r_page->page_size)) {
|
||||
if (log->page_size != t32 ||
|
||||
log->page_size != le32_to_cpu(log->rst_info.r_page->page_size)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If the file size has shrunk then we won't mount it. */
|
||||
if (l_size < le64_to_cpu(ra2->l_size)) {
|
||||
if (log->l_size < le64_to_cpu(ra2->l_size)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_init_pg_hdr(log, page_size, page_size,
|
||||
le16_to_cpu(rst_info.r_page->major_ver),
|
||||
le16_to_cpu(rst_info.r_page->minor_ver));
|
||||
log_init_pg_hdr(log, le16_to_cpu(log->rst_info.r_page->major_ver),
|
||||
le16_to_cpu(log->rst_info.r_page->minor_ver));
|
||||
|
||||
log->l_size = le64_to_cpu(ra2->l_size);
|
||||
log->seq_num_bits = le32_to_cpu(ra2->seq_num_bits);
|
||||
@ -3945,7 +3929,7 @@ init_log_instance:
|
||||
log->seq_num_mask = (8 << log->file_data_bits) - 1;
|
||||
log->last_lsn = le64_to_cpu(ra2->current_lsn);
|
||||
log->seq_num = log->last_lsn >> log->file_data_bits;
|
||||
log->ra_off = le16_to_cpu(rst_info.r_page->ra_off);
|
||||
log->ra_off = le16_to_cpu(log->rst_info.r_page->ra_off);
|
||||
log->restart_size = log->sys_page_size - log->ra_off;
|
||||
log->record_header_len = le16_to_cpu(ra2->rec_hdr_len);
|
||||
log->ra_size = le16_to_cpu(ra2->ra_len);
|
||||
@ -4045,7 +4029,7 @@ find_oldest:
|
||||
log->current_avail = current_log_avail(log);
|
||||
|
||||
/* Remember which restart area to write first. */
|
||||
log->init_ra = rst_info.vbo;
|
||||
log->init_ra = log->rst_info.vbo;
|
||||
|
||||
process_log:
|
||||
/* 1.0, 1.1, 2.0 log->major_ver/minor_ver - short values. */
|
||||
@ -4105,7 +4089,7 @@ process_log:
|
||||
log->client_id.seq_num = cr->seq_num;
|
||||
log->client_id.client_idx = client;
|
||||
|
||||
err = read_rst_area(log, &rst, &ra_lsn);
|
||||
err = read_rst_area(log, &rst, &checkpt_lsn);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -4114,9 +4098,8 @@ process_log:
|
||||
|
||||
bytes_per_attr_entry = !rst->major_ver ? 0x2C : 0x28;
|
||||
|
||||
checkpt_lsn = le64_to_cpu(rst->check_point_start);
|
||||
if (!checkpt_lsn)
|
||||
checkpt_lsn = ra_lsn;
|
||||
if (rst->check_point_start)
|
||||
checkpt_lsn = le64_to_cpu(rst->check_point_start);
|
||||
|
||||
/* Allocate and Read the Transaction Table. */
|
||||
if (!rst->transact_table_len)
|
||||
@ -4330,23 +4313,20 @@ check_attr_table:
|
||||
lcb = NULL;
|
||||
|
||||
check_attribute_names2:
|
||||
if (!rst->attr_names_len)
|
||||
goto trace_attribute_table;
|
||||
|
||||
ane = attr_names;
|
||||
if (!oatbl)
|
||||
goto trace_attribute_table;
|
||||
while (ane->off) {
|
||||
/* TODO: Clear table on exit! */
|
||||
oe = Add2Ptr(oatbl, le16_to_cpu(ane->off));
|
||||
t16 = le16_to_cpu(ane->name_bytes);
|
||||
oe->name_len = t16 / sizeof(short);
|
||||
oe->ptr = ane->name;
|
||||
oe->is_attr_name = 2;
|
||||
ane = Add2Ptr(ane, sizeof(struct ATTR_NAME_ENTRY) + t16);
|
||||
if (rst->attr_names_len && oatbl) {
|
||||
struct ATTR_NAME_ENTRY *ane = attr_names;
|
||||
while (ane->off) {
|
||||
/* TODO: Clear table on exit! */
|
||||
oe = Add2Ptr(oatbl, le16_to_cpu(ane->off));
|
||||
t16 = le16_to_cpu(ane->name_bytes);
|
||||
oe->name_len = t16 / sizeof(short);
|
||||
oe->ptr = ane->name;
|
||||
oe->is_attr_name = 2;
|
||||
ane = Add2Ptr(ane,
|
||||
sizeof(struct ATTR_NAME_ENTRY) + t16);
|
||||
}
|
||||
}
|
||||
|
||||
trace_attribute_table:
|
||||
/*
|
||||
* If the checkpt_lsn is zero, then this is a freshly
|
||||
* formatted disk and we have no work to do.
|
||||
@ -5189,7 +5169,7 @@ out:
|
||||
kfree(oatbl);
|
||||
kfree(dptbl);
|
||||
kfree(attr_names);
|
||||
kfree(rst_info.r_page);
|
||||
kfree(log->rst_info.r_page);
|
||||
|
||||
kfree(ra);
|
||||
kfree(log->one_page_buf);
|
||||
|
@ -853,7 +853,8 @@ void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
|
||||
/*
|
||||
* sb can be NULL here. In this case sbi->flags should be 0 too.
|
||||
*/
|
||||
if (!sb || !(sbi->flags & NTFS_FLAGS_MFTMIRR))
|
||||
if (!sb || !(sbi->flags & NTFS_FLAGS_MFTMIRR) ||
|
||||
unlikely(ntfs3_forced_shutdown(sb)))
|
||||
return;
|
||||
|
||||
blocksize = sb->s_blocksize;
|
||||
@ -1006,6 +1007,30 @@ static inline __le32 security_hash(const void *sd, size_t bytes)
|
||||
return cpu_to_le32(hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* simple wrapper for sb_bread_unmovable.
|
||||
*/
|
||||
struct buffer_head *ntfs_bread(struct super_block *sb, sector_t block)
|
||||
{
|
||||
struct ntfs_sb_info *sbi = sb->s_fs_info;
|
||||
struct buffer_head *bh;
|
||||
|
||||
if (unlikely(block >= sbi->volume.blocks)) {
|
||||
/* prevent generic message "attempt to access beyond end of device" */
|
||||
ntfs_err(sb, "try to read out of volume at offset 0x%llx",
|
||||
(u64)block << sb->s_blocksize_bits);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bh = sb_bread_unmovable(sb, block);
|
||||
if (bh)
|
||||
return bh;
|
||||
|
||||
ntfs_err(sb, "failed to read volume at offset 0x%llx",
|
||||
(u64)block << sb->s_blocksize_bits);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ntfs_sb_read(struct super_block *sb, u64 lbo, size_t bytes, void *buffer)
|
||||
{
|
||||
struct block_device *bdev = sb->s_bdev;
|
||||
@ -2128,8 +2153,8 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
|
||||
if (le32_to_cpu(d_security->size) == new_sec_size &&
|
||||
d_security->key.hash == hash_key.hash &&
|
||||
!memcmp(d_security + 1, sd, size_sd)) {
|
||||
*security_id = d_security->key.sec_id;
|
||||
/* Such security already exists. */
|
||||
*security_id = d_security->key.sec_id;
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
@ -1462,7 +1462,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
goto out2;
|
||||
|
||||
if (in->name == I30_NAME) {
|
||||
ni->vfs_inode.i_size = data_size;
|
||||
i_size_write(&ni->vfs_inode, data_size);
|
||||
inode_set_bytes(&ni->vfs_inode, alloc_size);
|
||||
}
|
||||
|
||||
@ -1544,7 +1544,7 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
}
|
||||
|
||||
if (in->name == I30_NAME)
|
||||
ni->vfs_inode.i_size = data_size;
|
||||
i_size_write(&ni->vfs_inode, data_size);
|
||||
|
||||
*vbn = bit << indx->idx2vbn_bits;
|
||||
|
||||
@ -2090,7 +2090,7 @@ static int indx_shrink(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
return err;
|
||||
|
||||
if (in->name == I30_NAME)
|
||||
ni->vfs_inode.i_size = new_data;
|
||||
i_size_write(&ni->vfs_inode, new_data);
|
||||
|
||||
bpb = bitmap_size(bit);
|
||||
if (bpb * 8 == nbits)
|
||||
@ -2576,7 +2576,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
err = attr_set_size(ni, ATTR_ALLOC, in->name, in->name_len,
|
||||
&indx->alloc_run, 0, NULL, false, NULL);
|
||||
if (in->name == I30_NAME)
|
||||
ni->vfs_inode.i_size = 0;
|
||||
i_size_write(&ni->vfs_inode, 0);
|
||||
|
||||
err = ni_remove_attr(ni, ATTR_ALLOC, in->name, in->name_len,
|
||||
false, NULL);
|
||||
|
@ -345,9 +345,7 @@ next_attr:
|
||||
inode->i_size = le16_to_cpu(rp.SymbolicLinkReparseBuffer
|
||||
.PrintNameLength) /
|
||||
sizeof(u16);
|
||||
|
||||
ni->i_valid = inode->i_size;
|
||||
|
||||
/* Clear directory bit. */
|
||||
if (ni->ni_flags & NI_FLAG_DIR) {
|
||||
indx_clear(&ni->dir);
|
||||
@ -412,7 +410,6 @@ end_enum:
|
||||
goto out;
|
||||
|
||||
if (!is_match && name) {
|
||||
/* Reuse rec as buffer for ascii name. */
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
@ -427,6 +424,7 @@ end_enum:
|
||||
|
||||
if (names != le16_to_cpu(rec->hard_links)) {
|
||||
/* Correct minor error on the fly. Do not mark inode as dirty. */
|
||||
ntfs_inode_warn(inode, "Correct links count -> %u.", names);
|
||||
rec->hard_links = cpu_to_le16(names);
|
||||
ni->mi.dirty = true;
|
||||
}
|
||||
@ -653,9 +651,10 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo,
|
||||
off = vbo & (PAGE_SIZE - 1);
|
||||
folio_set_bh(bh, folio, off);
|
||||
|
||||
err = bh_read(bh, 0);
|
||||
if (err < 0)
|
||||
if (bh_read(bh, 0) < 0) {
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
folio_zero_segment(folio, off + voff, off + block_size);
|
||||
}
|
||||
}
|
||||
@ -853,9 +852,13 @@ static int ntfs_resident_writepage(struct folio *folio,
|
||||
struct writeback_control *wbc, void *data)
|
||||
{
|
||||
struct address_space *mapping = data;
|
||||
struct ntfs_inode *ni = ntfs_i(mapping->host);
|
||||
struct inode *inode = mapping->host;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
int ret;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
ni_lock(ni);
|
||||
ret = attr_data_write_resident(ni, &folio->page);
|
||||
ni_unlock(ni);
|
||||
@ -869,7 +872,12 @@ static int ntfs_resident_writepage(struct folio *folio,
|
||||
static int ntfs_writepages(struct address_space *mapping,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
if (is_resident(ntfs_i(mapping->host)))
|
||||
struct inode *inode = mapping->host;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
if (is_resident(ntfs_i(inode)))
|
||||
return write_cache_pages(mapping, wbc, ntfs_resident_writepage,
|
||||
mapping);
|
||||
return mpage_writepages(mapping, wbc, ntfs_get_block);
|
||||
@ -889,6 +897,9 @@ int ntfs_write_begin(struct file *file, struct address_space *mapping,
|
||||
struct inode *inode = mapping->host;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
*pagep = NULL;
|
||||
if (is_resident(ni)) {
|
||||
struct page *page =
|
||||
@ -974,7 +985,7 @@ int ntfs_write_end(struct file *file, struct address_space *mapping, loff_t pos,
|
||||
}
|
||||
|
||||
if (pos + err > inode->i_size) {
|
||||
inode->i_size = pos + err;
|
||||
i_size_write(inode, pos + err);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@ -1306,6 +1317,11 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
|
||||
goto out1;
|
||||
}
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(sb))) {
|
||||
err = -EIO;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
/* Mark rw ntfs as dirty. it will be cleared at umount. */
|
||||
ntfs_set_state(sbi, NTFS_DIRTY_DIRTY);
|
||||
|
||||
|
@ -181,6 +181,9 @@ static int ntfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
struct ntfs_inode *ni = ntfs_i(dir);
|
||||
int err;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
ni_lock_dir(ni);
|
||||
|
||||
err = ntfs_unlink_inode(dir, dentry);
|
||||
@ -199,6 +202,9 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||
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);
|
||||
|
||||
@ -227,6 +233,9 @@ static int ntfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
struct ntfs_inode *ni = ntfs_i(dir);
|
||||
int err;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
ni_lock_dir(ni);
|
||||
|
||||
err = ntfs_unlink_inode(dir, dentry);
|
||||
@ -264,6 +273,9 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir,
|
||||
1024);
|
||||
static_assert(PATH_MAX >= 4 * 1024);
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(sb)))
|
||||
return -EIO;
|
||||
|
||||
if (flags & ~RENAME_NOREPLACE)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -523,12 +523,10 @@ struct ATTR_LIST_ENTRY {
|
||||
__le64 vcn; // 0x08: Starting VCN of this attribute.
|
||||
struct MFT_REF ref; // 0x10: MFT record number with attribute.
|
||||
__le16 id; // 0x18: struct ATTRIB ID.
|
||||
__le16 name[3]; // 0x1A: Just to align. To get real name can use bNameOffset.
|
||||
__le16 name[]; // 0x1A: To get real name use name_off.
|
||||
|
||||
}; // sizeof(0x20)
|
||||
|
||||
static_assert(sizeof(struct ATTR_LIST_ENTRY) == 0x20);
|
||||
|
||||
static inline u32 le_size(u8 name_len)
|
||||
{
|
||||
return ALIGN(offsetof(struct ATTR_LIST_ENTRY, name) +
|
||||
|
@ -61,6 +61,8 @@ enum utf16_endian;
|
||||
|
||||
/* sbi->flags */
|
||||
#define NTFS_FLAGS_NODISCARD 0x00000001
|
||||
/* ntfs in shutdown state. */
|
||||
#define NTFS_FLAGS_SHUTDOWN_BIT 0x00000002 /* == 4*/
|
||||
/* Set when LogFile is replaying. */
|
||||
#define NTFS_FLAGS_LOG_REPLAYING 0x00000008
|
||||
/* Set when we changed first MFT's which copy must be updated in $MftMirr. */
|
||||
@ -226,7 +228,7 @@ struct ntfs_sb_info {
|
||||
u64 maxbytes; // Maximum size for normal files.
|
||||
u64 maxbytes_sparse; // Maximum size for sparse file.
|
||||
|
||||
u32 flags; // See NTFS_FLAGS_XXX.
|
||||
unsigned long flags; // See NTFS_FLAGS_
|
||||
|
||||
CLST zone_max; // Maximum MFT zone length in clusters
|
||||
CLST bad_clusters; // The count of marked bad clusters.
|
||||
@ -473,7 +475,7 @@ bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn,
|
||||
int al_update(struct ntfs_inode *ni, int sync);
|
||||
static inline size_t al_aligned(size_t size)
|
||||
{
|
||||
return (size + 1023) & ~(size_t)1023;
|
||||
return size_add(size, 1023) & ~(size_t)1023;
|
||||
}
|
||||
|
||||
/* Globals from bitfunc.c */
|
||||
@ -500,6 +502,8 @@ int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
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);
|
||||
long ntfs_ioctl(struct file *filp, u32 cmd, unsigned long arg);
|
||||
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;
|
||||
@ -584,6 +588,7 @@ bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes);
|
||||
int log_replay(struct ntfs_inode *ni, bool *initialized);
|
||||
|
||||
/* Globals from fsntfs.c */
|
||||
struct buffer_head *ntfs_bread(struct super_block *sb, sector_t block);
|
||||
bool ntfs_fix_pre_write(struct NTFS_RECORD_HEADER *rhdr, size_t bytes);
|
||||
int ntfs_fix_post_read(struct NTFS_RECORD_HEADER *rhdr, size_t bytes,
|
||||
bool simple);
|
||||
@ -872,7 +877,7 @@ int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode,
|
||||
|
||||
int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry);
|
||||
ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
||||
extern const struct xattr_handler * const ntfs_xattr_handlers[];
|
||||
extern const struct xattr_handler *const ntfs_xattr_handlers[];
|
||||
|
||||
int ntfs_save_wsl_perm(struct inode *inode, __le16 *ea_size);
|
||||
void ntfs_get_wsl_perm(struct inode *inode);
|
||||
@ -999,6 +1004,11 @@ static inline struct ntfs_sb_info *ntfs_sb(struct super_block *sb)
|
||||
return sb->s_fs_info;
|
||||
}
|
||||
|
||||
static inline int ntfs3_forced_shutdown(struct super_block *sb)
|
||||
{
|
||||
return test_bit(NTFS_FLAGS_SHUTDOWN_BIT, &ntfs_sb(sb)->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_up_cluster - Align up on cluster boundary.
|
||||
*/
|
||||
@ -1025,19 +1035,6 @@ static inline u64 bytes_to_block(const struct super_block *sb, u64 size)
|
||||
return (size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
|
||||
}
|
||||
|
||||
static inline struct buffer_head *ntfs_bread(struct super_block *sb,
|
||||
sector_t block)
|
||||
{
|
||||
struct buffer_head *bh = sb_bread(sb, block);
|
||||
|
||||
if (bh)
|
||||
return bh;
|
||||
|
||||
ntfs_err(sb, "failed to read volume at offset 0x%llx",
|
||||
(u64)block << sb->s_blocksize_bits);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct ntfs_inode *ntfs_i(struct inode *inode)
|
||||
{
|
||||
return container_of(inode, struct ntfs_inode, vfs_inode);
|
||||
|
@ -279,7 +279,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
if (t16 > asize)
|
||||
return NULL;
|
||||
|
||||
if (t16 + le32_to_cpu(attr->res.data_size) > asize)
|
||||
if (le32_to_cpu(attr->res.data_size) > asize - t16)
|
||||
return NULL;
|
||||
|
||||
t32 = sizeof(short) * attr->name_len;
|
||||
@ -535,8 +535,20 @@ bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi,
|
||||
return false;
|
||||
|
||||
if (ni && is_attr_indexed(attr)) {
|
||||
le16_add_cpu(&ni->mi.mrec->hard_links, -1);
|
||||
ni->mi.dirty = true;
|
||||
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) {
|
||||
/* minor error. Not critical. */
|
||||
} else {
|
||||
ni->mi.mrec->hard_links = cpu_to_le16(links - 1);
|
||||
ni->mi.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
used -= asize;
|
||||
|
@ -122,13 +122,12 @@ void ntfs_inode_printk(struct inode *inode, const char *fmt, ...)
|
||||
|
||||
if (name) {
|
||||
struct dentry *de = d_find_alias(inode);
|
||||
const u32 name_len = ARRAY_SIZE(s_name_buf) - 1;
|
||||
|
||||
if (de) {
|
||||
spin_lock(&de->d_lock);
|
||||
snprintf(name, name_len, " \"%s\"", de->d_name.name);
|
||||
snprintf(name, sizeof(s_name_buf), " \"%s\"",
|
||||
de->d_name.name);
|
||||
spin_unlock(&de->d_lock);
|
||||
name[name_len] = 0; /* To be sure. */
|
||||
} else {
|
||||
name[0] = 0;
|
||||
}
|
||||
@ -625,7 +624,7 @@ static void ntfs3_free_sbi(struct ntfs_sb_info *sbi)
|
||||
{
|
||||
kfree(sbi->new_rec);
|
||||
kvfree(ntfs_put_shared(sbi->upcase));
|
||||
kfree(sbi->def_table);
|
||||
kvfree(sbi->def_table);
|
||||
kfree(sbi->compress.lznt);
|
||||
#ifdef CONFIG_NTFS3_LZX_XPRESS
|
||||
xpress_free_decompressor(sbi->compress.xpress);
|
||||
@ -714,6 +713,14 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_shutdown - super_operations::shutdown
|
||||
*/
|
||||
static void ntfs_shutdown(struct super_block *sb)
|
||||
{
|
||||
set_bit(NTFS_FLAGS_SHUTDOWN_BIT, &ntfs_sb(sb)->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_sync_fs - super_operations::sync_fs
|
||||
*/
|
||||
@ -724,6 +731,9 @@ static int ntfs_sync_fs(struct super_block *sb, int wait)
|
||||
struct ntfs_inode *ni;
|
||||
struct inode *inode;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(sb)))
|
||||
return -EIO;
|
||||
|
||||
ni = sbi->security.ni;
|
||||
if (ni) {
|
||||
inode = &ni->vfs_inode;
|
||||
@ -763,6 +773,7 @@ static const struct super_operations ntfs_sops = {
|
||||
.put_super = ntfs_put_super,
|
||||
.statfs = ntfs_statfs,
|
||||
.show_options = ntfs_show_options,
|
||||
.shutdown = ntfs_shutdown,
|
||||
.sync_fs = ntfs_sync_fs,
|
||||
.write_inode = ntfs3_write_inode,
|
||||
};
|
||||
@ -866,6 +877,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
|
||||
u16 fn, ao;
|
||||
u8 cluster_bits;
|
||||
u32 boot_off = 0;
|
||||
sector_t boot_block = 0;
|
||||
const char *hint = "Primary boot";
|
||||
|
||||
/* Save original dev_size. Used with alternative boot. */
|
||||
@ -873,11 +885,11 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
|
||||
|
||||
sbi->volume.blocks = dev_size >> PAGE_SHIFT;
|
||||
|
||||
bh = ntfs_bread(sb, 0);
|
||||
read_boot:
|
||||
bh = ntfs_bread(sb, boot_block);
|
||||
if (!bh)
|
||||
return -EIO;
|
||||
return boot_block ? -EINVAL : -EIO;
|
||||
|
||||
check_boot:
|
||||
err = -EINVAL;
|
||||
|
||||
/* Corrupted image; do not read OOB */
|
||||
@ -1108,26 +1120,24 @@ check_boot:
|
||||
}
|
||||
|
||||
out:
|
||||
if (err == -EINVAL && !bh->b_blocknr && dev_size0 > PAGE_SHIFT) {
|
||||
brelse(bh);
|
||||
|
||||
if (err == -EINVAL && !boot_block && dev_size0 > PAGE_SHIFT) {
|
||||
u32 block_size = min_t(u32, sector_size, PAGE_SIZE);
|
||||
u64 lbo = dev_size0 - sizeof(*boot);
|
||||
|
||||
/*
|
||||
* Try alternative boot (last sector)
|
||||
*/
|
||||
brelse(bh);
|
||||
|
||||
sb_set_blocksize(sb, block_size);
|
||||
bh = ntfs_bread(sb, lbo >> blksize_bits(block_size));
|
||||
if (!bh)
|
||||
return -EINVAL;
|
||||
|
||||
boot_block = lbo >> blksize_bits(block_size);
|
||||
boot_off = lbo & (block_size - 1);
|
||||
hint = "Alternative boot";
|
||||
dev_size = dev_size0; /* restore original size. */
|
||||
goto check_boot;
|
||||
if (boot_block && block_size >= boot_off + sizeof(*boot)) {
|
||||
/*
|
||||
* Try alternative boot (last sector)
|
||||
*/
|
||||
sb_set_blocksize(sb, block_size);
|
||||
hint = "Alternative boot";
|
||||
dev_size = dev_size0; /* restore original size. */
|
||||
goto read_boot;
|
||||
}
|
||||
}
|
||||
brelse(bh);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -219,6 +219,9 @@ static ssize_t ntfs_list_ea(struct ntfs_inode *ni, char *buffer,
|
||||
if (!ea->name_len)
|
||||
break;
|
||||
|
||||
if (ea->name_len > ea_size)
|
||||
break;
|
||||
|
||||
if (buffer) {
|
||||
/* Check if we can use field ea->name */
|
||||
if (off + ea_size > size)
|
||||
@ -744,6 +747,9 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
|
||||
int err;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
/* Dispatch request. */
|
||||
if (!strcmp(name, SYSTEM_DOS_ATTRIB)) {
|
||||
/* system.dos_attrib */
|
||||
|
Loading…
x
Reference in New Issue
Block a user