summaryrefslogtreecommitdiff
path: root/fs/ntfs3/fsntfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ntfs3/fsntfs.c')
-rw-r--r--fs/ntfs3/fsntfs.c112
1 files changed, 70 insertions, 42 deletions
diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c
index bd67ba7b5015..0df2aa81d884 100644
--- a/fs/ntfs3/fsntfs.c
+++ b/fs/ntfs3/fsntfs.c
@@ -445,36 +445,59 @@ up_write:
}
/*
- * ntfs_check_for_free_space
+ * ntfs_check_free_space
*
* Check if it is possible to allocate 'clen' clusters and 'mlen' Mft records
*/
-bool ntfs_check_for_free_space(struct ntfs_sb_info *sbi, CLST clen, CLST mlen)
+bool ntfs_check_free_space(struct ntfs_sb_info *sbi, CLST clen, CLST mlen,
+ bool da)
{
size_t free, zlen, avail;
struct wnd_bitmap *wnd;
+ CLST da_clusters = ntfs_get_da(sbi);
wnd = &sbi->used.bitmap;
down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
free = wnd_zeroes(wnd);
+
+ if (free >= da_clusters) {
+ free -= da_clusters;
+ } else {
+ free = 0;
+ }
+
zlen = min_t(size_t, NTFS_MIN_MFT_ZONE, wnd_zone_len(wnd));
up_read(&wnd->rw_lock);
- if (free < zlen + clen)
+ if (free < zlen + clen) {
return false;
+ }
avail = free - (zlen + clen);
- wnd = &sbi->mft.bitmap;
- down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
- free = wnd_zeroes(wnd);
- zlen = wnd_zone_len(wnd);
- up_read(&wnd->rw_lock);
+ /*
+ * When delalloc is active then keep in mind some reserved space.
+ * The worst case: 1 mft record per each ~500 clusters.
+ */
+ if (da) {
+ /* 1 mft record per each 1024 clusters. */
+ mlen += da_clusters >> 10;
+ }
+
+ if (mlen || !avail) {
+ wnd = &sbi->mft.bitmap;
+ down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
+ free = wnd_zeroes(wnd);
+ zlen = wnd_zone_len(wnd);
+ up_read(&wnd->rw_lock);
- if (free >= zlen + mlen)
- return true;
+ if (free < zlen + mlen &&
+ avail < bytes_to_cluster(sbi, mlen << sbi->record_bits)) {
+ return false;
+ }
+ }
- return avail >= bytes_to_cluster(sbi, mlen << sbi->record_bits);
+ return true;
}
/*
@@ -509,8 +532,8 @@ static int ntfs_extend_mft(struct ntfs_sb_info *sbi)
/* Step 1: Resize $MFT::DATA. */
down_write(&ni->file.run_lock);
- err = attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run,
- new_mft_bytes, NULL, false, &attr);
+ err = attr_set_size_ex(ni, ATTR_DATA, NULL, 0, &ni->file.run,
+ new_mft_bytes, NULL, false, &attr, false);
if (err) {
up_write(&ni->file.run_lock);
@@ -525,7 +548,7 @@ static int ntfs_extend_mft(struct ntfs_sb_info *sbi)
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);
+ new_bitmap_bytes, &new_bitmap_bytes, true);
/* Refresh MFT Zone if necessary. */
down_write_nested(&sbi->used.bitmap.rw_lock, BITMAP_MUTEX_CLUSTERS);
@@ -843,9 +866,8 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
/*
* ntfs_update_mftmirr - Update $MFTMirr data.
*/
-void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
+void ntfs_update_mftmirr(struct ntfs_sb_info *sbi)
{
- int err;
struct super_block *sb = sbi->sb;
u32 blocksize, bytes;
sector_t block1, block2;
@@ -875,9 +897,7 @@ void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
return;
}
- if (buffer_locked(bh2))
- __wait_on_buffer(bh2);
-
+ wait_on_buffer(bh2);
lock_buffer(bh2);
memcpy(bh2->b_data, bh1->b_data, blocksize);
set_buffer_uptodate(bh2);
@@ -886,12 +906,7 @@ void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
put_bh(bh1);
bh1 = NULL;
-
- err = wait ? sync_dirty_buffer(bh2) : 0;
-
put_bh(bh2);
- if (err)
- return;
}
sbi->flags &= ~NTFS_FLAGS_MFTMIRR;
@@ -1069,9 +1084,7 @@ int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes,
return -ENOMEM;
}
- if (buffer_locked(bh))
- __wait_on_buffer(bh);
-
+ wait_on_buffer(bh);
lock_buffer(bh);
if (buf) {
memcpy(bh->b_data + off, buf, op);
@@ -1168,11 +1181,13 @@ struct buffer_head *ntfs_bread_run(struct ntfs_sb_info *sbi,
return ntfs_bread(sb, lbo >> sb->s_blocksize_bits);
}
-int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
- u64 vbo, void *buf, u32 bytes, struct ntfs_buffers *nb)
+int ntfs_read_run_nb_ra(struct ntfs_sb_info *sbi, const struct runs_tree *run,
+ u64 vbo, void *buf, u32 bytes, struct ntfs_buffers *nb,
+ struct file_ra_state *ra)
{
int err;
struct super_block *sb = sbi->sb;
+ struct address_space *mapping = sb->s_bdev->bd_mapping;
u32 blocksize = sb->s_blocksize;
u8 cluster_bits = sbi->cluster_bits;
u32 off = vbo & sbi->cluster_mask;
@@ -1212,10 +1227,22 @@ int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
nb->bytes = bytes;
}
+ if (ra && !ra->ra_pages)
+ file_ra_state_init(ra, mapping);
+
for (;;) {
u32 len32 = len >= bytes ? bytes : len;
sector_t block = lbo >> sb->s_blocksize_bits;
+ if (ra) {
+ pgoff_t index = lbo >> PAGE_SHIFT;
+ if (!ra_has_index(ra, index)) {
+ page_cache_sync_readahead(mapping, ra, NULL,
+ index, 1);
+ ra->prev_pos = (loff_t)index << PAGE_SHIFT;
+ }
+ }
+
do {
u32 op = blocksize - off;
@@ -1252,6 +1279,12 @@ int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
} while (len32);
+ if (!run) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* Get next fragment to read. */
vcn_next = vcn + clen;
if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
vcn != vcn_next) {
@@ -1286,11 +1319,11 @@ out:
*
* Return: < 0 if error, 0 if ok, -E_NTFS_FIXUP if need to update fixups.
*/
-int ntfs_read_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
- struct NTFS_RECORD_HEADER *rhdr, u32 bytes,
- struct ntfs_buffers *nb)
+int ntfs_read_bh_ra(struct ntfs_sb_info *sbi, const struct runs_tree *run,
+ u64 vbo, struct NTFS_RECORD_HEADER *rhdr, u32 bytes,
+ struct ntfs_buffers *nb, struct file_ra_state *ra)
{
- int err = ntfs_read_run_nb(sbi, run, vbo, rhdr, bytes, nb);
+ int err = ntfs_read_run_nb_ra(sbi, run, vbo, rhdr, bytes, nb, ra);
if (err)
return err;
@@ -1347,12 +1380,9 @@ int ntfs_get_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
err = -ENOMEM;
goto out;
}
- if (buffer_locked(bh))
- __wait_on_buffer(bh);
-
+ wait_on_buffer(bh);
lock_buffer(bh);
- if (!buffer_uptodate(bh))
- {
+ if (!buffer_uptodate(bh)) {
memset(bh->b_data, 0, blocksize);
set_buffer_uptodate(bh);
}
@@ -1427,9 +1457,7 @@ int ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr,
if (op > bytes)
op = bytes;
- if (buffer_locked(bh))
- __wait_on_buffer(bh);
-
+ wait_on_buffer(bh);
lock_buffer(bh);
bh_data = bh->b_data + off;
@@ -2186,7 +2214,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
if (new_sds_size > ni->vfs_inode.i_size) {
err = attr_set_size(ni, ATTR_DATA, SDS_NAME,
ARRAY_SIZE(SDS_NAME), &ni->file.run,
- new_sds_size, &new_sds_size, false, NULL);
+ new_sds_size, &new_sds_size, false);
if (err)
goto out;
}