summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-08-07 10:42:09 -0700
committerDavid S. Miller <davem@davemloft.net>2017-08-07 10:42:09 -0700
commitfde6af4729b005dc9dc936b0ed9f1b27b5b2d0f4 (patch)
treefb52e170a7b2130b8a5266ac665d4314447fef95 /fs
parent71feeef678056a640466a6d1faee3a7bcbbccab9 (diff)
parenta8ffcc741acb3c7f3dcf4c7d001209aa0995a5f1 (diff)
downloadop-kernel-dev-fde6af4729b005dc9dc936b0ed9f1b27b5b2d0f4.zip
op-kernel-dev-fde6af4729b005dc9dc936b0ed9f1b27b5b2d0f4.tar.gz
Merge tag 'mlx5-shared-2017-08-07' of git://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux
Saeed Mahameed says: ==================== mlx5-shared-2017-08-07 This series includes some mlx5 updates for both net-next and rdma trees. From Saeed, Core driver updates to allow selectively building the driver with or without some large driver components, such as - E-Switch (Ethernet SRIOV support). - Multi-Physical Function Switch (MPFs) support. For that we split E-Switch and MPFs functionalities into separate files. From Erez, Delay mlx5_core events when mlx5 interfaces, namely mlx5_ib, registration is taking place and until it completes. From Rabie, Increase the maximum supported flow counters. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/acl.c25
-rw-r--r--fs/ext4/ext4.h13
-rw-r--r--fs/ext4/ext4_jbd2.h3
-rw-r--r--fs/ext4/extents.c11
-rw-r--r--fs/ext4/file.c3
-rw-r--r--fs/ext4/inode.c198
-rw-r--r--fs/ext4/ioctl.c27
-rw-r--r--fs/ext4/mballoc.c15
-rw-r--r--fs/ext4/namei.c64
-rw-r--r--fs/ext4/resize.c3
-rw-r--r--fs/ext4/super.c2
-rw-r--r--fs/ext4/xattr.c87
-rw-r--r--fs/nfs/nfs4client.c3
-rw-r--r--fs/nfs/nfs4proc.c27
-rw-r--r--fs/nfs/nfs4xdr.c2
-rw-r--r--fs/ocfs2/acl.c24
-rw-r--r--fs/userfaultfd.c5
17 files changed, 307 insertions, 205 deletions
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index 09441ae..46ff222 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -193,13 +193,6 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
switch (type) {
case ACL_TYPE_ACCESS:
name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
- if (acl) {
- error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
- if (error)
- return error;
- inode->i_ctime = current_time(inode);
- ext4_mark_inode_dirty(handle, inode);
- }
break;
case ACL_TYPE_DEFAULT:
@@ -221,8 +214,9 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
value, size, xattr_flags);
kfree(value);
- if (!error)
+ if (!error) {
set_cached_acl(inode, type, acl);
+ }
return error;
}
@@ -233,6 +227,8 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type)
handle_t *handle;
int error, credits, retries = 0;
size_t acl_size = acl ? ext4_acl_size(acl->a_count) : 0;
+ umode_t mode = inode->i_mode;
+ int update_mode = 0;
error = dquot_initialize(inode);
if (error)
@@ -247,7 +243,20 @@ retry:
if (IS_ERR(handle))
return PTR_ERR(handle);
+ if ((type == ACL_TYPE_ACCESS) && acl) {
+ error = posix_acl_update_mode(inode, &mode, &acl);
+ if (error)
+ goto out_stop;
+ update_mode = 1;
+ }
+
error = __ext4_set_acl(handle, inode, type, acl, 0 /* xattr_flags */);
+ if (!error && update_mode) {
+ inode->i_mode = mode;
+ inode->i_ctime = current_time(inode);
+ ext4_mark_inode_dirty(handle, inode);
+ }
+out_stop:
ext4_journal_stop(handle);
if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
goto retry;
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 9ebde0c..a2bb7d2 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -961,7 +961,7 @@ struct ext4_inode_info {
/*
* i_block_group is the number of the block group which contains
* this file's inode. Constant across the lifetime of the inode,
- * it is ued for making block allocation decisions - we try to
+ * it is used for making block allocation decisions - we try to
* place a file's data blocks near its inode block, and new inodes
* near to their parent directory's inode.
*/
@@ -1049,10 +1049,8 @@ struct ext4_inode_info {
ext4_group_t i_last_alloc_group;
/* allocation reservation info for delalloc */
- /* In case of bigalloc, these refer to clusters rather than blocks */
+ /* In case of bigalloc, this refer to clusters rather than blocks */
unsigned int i_reserved_data_blocks;
- unsigned int i_reserved_meta_blocks;
- unsigned int i_allocated_meta_blocks;
ext4_lblk_t i_da_metadata_calc_last_lblock;
int i_da_metadata_calc_len;
@@ -2022,7 +2020,8 @@ static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
#define is_dx(dir) (ext4_has_feature_dir_index((dir)->i_sb) && \
ext4_test_inode_flag((dir), EXT4_INODE_INDEX))
-#define EXT4_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT4_LINK_MAX)
+#define EXT4_DIR_LINK_MAX(dir) unlikely((dir)->i_nlink >= EXT4_LINK_MAX && \
+ !(ext4_has_feature_dir_nlink((dir)->i_sb) && is_dx(dir)))
#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
/* Legal values for the dx_root hash_version field: */
@@ -2462,6 +2461,8 @@ extern void ext4_process_freed_data(struct super_block *sb, tid_t commit_tid);
int ext4_inode_is_fast_symlink(struct inode *inode);
struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int);
struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int);
+int ext4_bread_batch(struct inode *inode, ext4_lblk_t block, int bh_count,
+ bool wait, struct buffer_head **bhs);
int ext4_get_block_unwritten(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create);
int ext4_get_block(struct inode *inode, sector_t iblock,
@@ -3074,7 +3075,7 @@ extern int ext4_handle_dirty_dirent_node(handle_t *handle,
struct inode *inode,
struct buffer_head *bh);
#define S_SHIFT 12
-static const unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = {
+static const unsigned char ext4_type_by_mode[(S_IFMT >> S_SHIFT) + 1] = {
[S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE,
[S_IFDIR >> S_SHIFT] = EXT4_FT_DIR,
[S_IFCHR >> S_SHIFT] = EXT4_FT_CHRDEV,
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index dabad1b..48143e3 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -227,6 +227,9 @@ int ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
+int ext4_expand_extra_isize(struct inode *inode,
+ unsigned int new_extra_isize,
+ struct ext4_iloc *iloc);
/*
* Wrapper functions with which ext4 calls into JBD.
*/
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index e0a8425..97f0fd0 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4652,7 +4652,7 @@ retry:
static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
ext4_lblk_t len, loff_t new_size,
- int flags, int mode)
+ int flags)
{
struct inode *inode = file_inode(file);
handle_t *handle;
@@ -4815,7 +4815,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
round_down(offset, 1 << blkbits) >> blkbits,
(round_up((offset + len), 1 << blkbits) -
round_down(offset, 1 << blkbits)) >> blkbits,
- new_size, flags, mode);
+ new_size, flags);
if (ret)
goto out_dio;
@@ -4841,7 +4841,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
inode->i_mtime = inode->i_ctime = current_time(inode);
ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
- flags, mode);
+ flags);
up_write(&EXT4_I(inode)->i_mmap_sem);
if (ret)
goto out_dio;
@@ -4976,8 +4976,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
ext4_inode_block_unlocked_dio(inode);
inode_dio_wait(inode);
- ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
- flags, mode);
+ ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags);
ext4_inode_resume_unlocked_dio(inode);
if (ret)
goto out;
@@ -5837,7 +5836,7 @@ ext4_swap_extents(handle_t *handle, struct inode *inode1,
if (e1_blk > lblk1)
next1 = e1_blk;
if (e2_blk > lblk2)
- next2 = e1_blk;
+ next2 = e2_blk;
/* Do we have something to swap */
if (next1 == EXT_MAX_BLOCKS || next2 == EXT_MAX_BLOCKS)
goto finish;
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 58294c9..0d7cf0c 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -537,6 +537,8 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
lastoff = page_offset(page);
bh = head = page_buffers(page);
do {
+ if (lastoff + bh->b_size <= startoff)
+ goto next;
if (buffer_uptodate(bh) ||
buffer_unwritten(bh)) {
if (whence == SEEK_DATA)
@@ -551,6 +553,7 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
unlock_page(page);
goto out;
}
+next:
lastoff += bh->b_size;
bh = bh->b_this_page;
} while (bh != head);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 3c600f0..c774bdc 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -892,7 +892,7 @@ static int ext4_dio_get_block_unwritten_async(struct inode *inode,
/*
* Get block function for non-AIO DIO writes when we create unwritten extent if
* blocks are not allocated yet. The extent will be converted to written
- * after IO is complete from ext4_ext_direct_IO() function.
+ * after IO is complete by ext4_direct_IO_write().
*/
static int ext4_dio_get_block_unwritten_sync(struct inode *inode,
sector_t iblock, struct buffer_head *bh_result, int create)
@@ -907,7 +907,7 @@ static int ext4_dio_get_block_unwritten_sync(struct inode *inode,
/*
* Mark inode as having pending DIO writes to unwritten extents.
- * ext4_ext_direct_IO() checks this flag and converts extents to
+ * ext4_direct_IO_write() checks this flag and converts extents to
* written.
*/
if (!ret && buffer_unwritten(bh_result))
@@ -1015,6 +1015,50 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
return ERR_PTR(-EIO);
}
+/* Read a contiguous batch of blocks. */
+int ext4_bread_batch(struct inode *inode, ext4_lblk_t block, int bh_count,
+ bool wait, struct buffer_head **bhs)
+{
+ int i, err;
+
+ for (i = 0; i < bh_count; i++) {
+ bhs[i] = ext4_getblk(NULL, inode, block + i, 0 /* map_flags */);
+ if (IS_ERR(bhs[i])) {
+ err = PTR_ERR(bhs[i]);
+ bh_count = i;
+ goto out_brelse;
+ }
+ }
+
+ for (i = 0; i < bh_count; i++)
+ /* Note that NULL bhs[i] is valid because of holes. */
+ if (bhs[i] && !buffer_uptodate(bhs[i]))
+ ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1,
+ &bhs[i]);
+
+ if (!wait)
+ return 0;
+
+ for (i = 0; i < bh_count; i++)
+ if (bhs[i])
+ wait_on_buffer(bhs[i]);
+
+ for (i = 0; i < bh_count; i++) {
+ if (bhs[i] && !buffer_uptodate(bhs[i])) {
+ err = -EIO;
+ goto out_brelse;
+ }
+ }
+ return 0;
+
+out_brelse:
+ for (i = 0; i < bh_count; i++) {
+ brelse(bhs[i]);
+ bhs[i] = NULL;
+ }
+ return err;
+}
+
int ext4_walk_page_buffers(handle_t *handle,
struct buffer_head *head,
unsigned from,
@@ -5658,22 +5702,16 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
return err;
}
-/*
- * Expand an inode by new_extra_isize bytes.
- * Returns 0 on success or negative error number on failure.
- */
-static int ext4_expand_extra_isize(struct inode *inode,
- unsigned int new_extra_isize,
- struct ext4_iloc iloc,
- handle_t *handle)
+static int __ext4_expand_extra_isize(struct inode *inode,
+ unsigned int new_extra_isize,
+ struct ext4_iloc *iloc,
+ handle_t *handle, int *no_expand)
{
struct ext4_inode *raw_inode;
struct ext4_xattr_ibody_header *header;
+ int error;
- if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
- return 0;
-
- raw_inode = ext4_raw_inode(&iloc);
+ raw_inode = ext4_raw_inode(iloc);
header = IHDR(inode, raw_inode);
@@ -5688,8 +5726,98 @@ static int ext4_expand_extra_isize(struct inode *inode,
}
/* try to expand with EAs present */
- return ext4_expand_extra_isize_ea(inode, new_extra_isize,
- raw_inode, handle);
+ error = ext4_expand_extra_isize_ea(inode, new_extra_isize,
+ raw_inode, handle);
+ if (error) {
+ /*
+ * Inode size expansion failed; don't try again
+ */
+ *no_expand = 1;
+ }
+
+ return error;
+}
+
+/*
+ * Expand an inode by new_extra_isize bytes.
+ * Returns 0 on success or negative error number on failure.
+ */
+static int ext4_try_to_expand_extra_isize(struct inode *inode,
+ unsigned int new_extra_isize,
+ struct ext4_iloc iloc,
+ handle_t *handle)
+{
+ int no_expand;
+ int error;
+
+ if (ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND))
+ return -EOVERFLOW;
+
+ /*
+ * In nojournal mode, we can immediately attempt to expand
+ * the inode. When journaled, we first need to obtain extra
+ * buffer credits since we may write into the EA block
+ * with this same handle. If journal_extend fails, then it will
+ * only result in a minor loss of functionality for that inode.
+ * If this is felt to be critical, then e2fsck should be run to
+ * force a large enough s_min_extra_isize.
+ */
+ if (ext4_handle_valid(handle) &&
+ jbd2_journal_extend(handle,
+ EXT4_DATA_TRANS_BLOCKS(inode->i_sb)) != 0)
+ return -ENOSPC;
+
+ if (ext4_write_trylock_xattr(inode, &no_expand) == 0)
+ return -EBUSY;
+
+ error = __ext4_expand_extra_isize(inode, new_extra_isize, &iloc,
+ handle, &no_expand);
+ ext4_write_unlock_xattr(inode, &no_expand);
+
+ return error;
+}
+
+int ext4_expand_extra_isize(struct inode *inode,
+ unsigned int new_extra_isize,
+ struct ext4_iloc *iloc)
+{
+ handle_t *handle;
+ int no_expand;
+ int error, rc;
+
+ if (ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) {
+ brelse(iloc->bh);
+ return -EOVERFLOW;
+ }
+
+ handle = ext4_journal_start(inode, EXT4_HT_INODE,
+ EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
+ if (IS_ERR(handle)) {
+ error = PTR_ERR(handle);
+ brelse(iloc->bh);
+ return error;
+ }
+
+ ext4_write_lock_xattr(inode, &no_expand);
+
+ BUFFER_TRACE(iloc.bh, "get_write_access");
+ error = ext4_journal_get_write_access(handle, iloc->bh);
+ if (error) {
+ brelse(iloc->bh);
+ goto out_stop;
+ }
+
+ error = __ext4_expand_extra_isize(inode, new_extra_isize, iloc,
+ handle, &no_expand);
+
+ rc = ext4_mark_iloc_dirty(handle, inode, iloc);
+ if (!error)
+ error = rc;
+
+ ext4_write_unlock_xattr(inode, &no_expand);
+out_stop:
+ ext4_journal_stop(handle);
+ return error;
}
/*
@@ -5709,44 +5837,18 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
{
struct ext4_iloc iloc;
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
- static unsigned int mnt_count;
- int err, ret;
+ int err;
might_sleep();
trace_ext4_mark_inode_dirty(inode, _RET_IP_);
err = ext4_reserve_inode_write(handle, inode, &iloc);
if (err)
return err;
- if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
- !ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) {
- /*
- * In nojournal mode, we can immediately attempt to expand
- * the inode. When journaled, we first need to obtain extra
- * buffer credits since we may write into the EA block
- * with this same handle. If journal_extend fails, then it will
- * only result in a minor loss of functionality for that inode.
- * If this is felt to be critical, then e2fsck should be run to
- * force a large enough s_min_extra_isize.
- */
- if (!ext4_handle_valid(handle) ||
- jbd2_journal_extend(handle,
- EXT4_DATA_TRANS_BLOCKS(inode->i_sb)) == 0) {
- ret = ext4_expand_extra_isize(inode,
- sbi->s_want_extra_isize,
- iloc, handle);
- if (ret) {
- if (mnt_count !=
- le16_to_cpu(sbi->s_es->s_mnt_count)) {
- ext4_warning(inode->i_sb,
- "Unable to expand inode %lu. Delete"
- " some EAs or run e2fsck.",
- inode->i_ino);
- mnt_count =
- le16_to_cpu(sbi->s_es->s_mnt_count);
- }
- }
- }
- }
+
+ if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize)
+ ext4_try_to_expand_extra_isize(inode, sbi->s_want_extra_isize,
+ iloc, handle);
+
return ext4_mark_iloc_dirty(handle, inode, &iloc);
}
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 42b3a73..afb66d4 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -64,18 +64,16 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2)
ei1 = EXT4_I(inode1);
ei2 = EXT4_I(inode2);
- memswap(&inode1->i_flags, &inode2->i_flags, sizeof(inode1->i_flags));
- memswap(&inode1->i_version, &inode2->i_version,
- sizeof(inode1->i_version));
- memswap(&inode1->i_blocks, &inode2->i_blocks,
- sizeof(inode1->i_blocks));
- memswap(&inode1->i_bytes, &inode2->i_bytes, sizeof(inode1->i_bytes));
- memswap(&inode1->i_atime, &inode2->i_atime, sizeof(inode1->i_atime));
- memswap(&inode1->i_mtime, &inode2->i_mtime, sizeof(inode1->i_mtime));
+ swap(inode1->i_flags, inode2->i_flags);
+ swap(inode1->i_version, inode2->i_version);
+ swap(inode1->i_blocks, inode2->i_blocks);
+ swap(inode1->i_bytes, inode2->i_bytes);
+ swap(inode1->i_atime, inode2->i_atime);
+ swap(inode1->i_mtime, inode2->i_mtime);
memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data));
- memswap(&ei1->i_flags, &ei2->i_flags, sizeof(ei1->i_flags));
- memswap(&ei1->i_disksize, &ei2->i_disksize, sizeof(ei1->i_disksize));
+ swap(ei1->i_flags, ei2->i_flags);
+ swap(ei1->i_disksize, ei2->i_disksize);
ext4_es_remove_extent(inode1, 0, EXT_MAX_BLOCKS);
ext4_es_remove_extent(inode2, 0, EXT_MAX_BLOCKS);
@@ -351,11 +349,14 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
raw_inode = ext4_raw_inode(&iloc);
if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
- err = -EOVERFLOW;
+ err = ext4_expand_extra_isize(inode,
+ EXT4_SB(sb)->s_want_extra_isize,
+ &iloc);
+ if (err)
+ goto out_unlock;
+ } else {
brelse(iloc.bh);
- goto out_unlock;
}
- brelse(iloc.bh);
dquot_initialize(inode);
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 581e357..5a10526 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2295,9 +2295,12 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
int err, buddy_loaded = 0;
struct ext4_buddy e4b;
struct ext4_group_info *grinfo;
+ unsigned char blocksize_bits = min_t(unsigned char,
+ sb->s_blocksize_bits,
+ EXT4_MAX_BLOCK_LOG_SIZE);
struct sg {
struct ext4_group_info info;
- ext4_grpblk_t counters[EXT4_MAX_BLOCK_LOG_SIZE + 2];
+ ext4_grpblk_t counters[blocksize_bits + 2];
} sg;
group--;
@@ -2306,8 +2309,6 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
" 2^0 2^1 2^2 2^3 2^4 2^5 2^6 "
" 2^7 2^8 2^9 2^10 2^11 2^12 2^13 ]\n");
- i = (sb->s_blocksize_bits + 2) * sizeof(sg.info.bb_counters[0]) +
- sizeof(struct ext4_group_info);
grinfo = ext4_get_group_info(sb, group);
/* Load the group info in memory only if not already loaded. */
if (unlikely(EXT4_MB_GRP_NEED_INIT(grinfo))) {
@@ -2319,7 +2320,7 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
buddy_loaded = 1;
}
- memcpy(&sg, ext4_get_group_info(sb, group), i);
+ memcpy(&sg, ext4_get_group_info(sb, group), sizeof(sg));
if (buddy_loaded)
ext4_mb_unload_buddy(&e4b);
@@ -2327,7 +2328,7 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg.info.bb_free,
sg.info.bb_fragments, sg.info.bb_first_free);
for (i = 0; i <= 13; i++)
- seq_printf(seq, " %-5u", i <= sb->s_blocksize_bits + 1 ?
+ seq_printf(seq, " %-5u", i <= blocksize_bits + 1 ?
sg.info.bb_counters[i] : 0);
seq_printf(seq, " ]\n");
@@ -2892,8 +2893,10 @@ void ext4_process_freed_data(struct super_block *sb, tid_t commit_tid)
break;
}
- if (discard_bio)
+ if (discard_bio) {
submit_bio_wait(discard_bio);
+ bio_put(discard_bio);
+ }
}
list_for_each_entry_safe(entry, tmp, &freed_data_list, efd_list)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 13f0cad..c1cf020 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1342,13 +1342,12 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
struct super_block *sb;
struct buffer_head *bh_use[NAMEI_RA_SIZE];
struct buffer_head *bh, *ret = NULL;
- ext4_lblk_t start, block, b;
+ ext4_lblk_t start, block;
const u8 *name = d_name->name;
- int ra_max = 0; /* Number of bh's in the readahead
+ size_t ra_max = 0; /* Number of bh's in the readahead
buffer, bh_use[] */
- int ra_ptr = 0; /* Current index into readahead
+ size_t ra_ptr = 0; /* Current index into readahead
buffer */
- int num = 0;
ext4_lblk_t nblocks;
int i, namelen, retval;
struct ext4_filename fname;
@@ -1411,31 +1410,17 @@ restart:
if (ra_ptr >= ra_max) {
/* Refill the readahead buffer */
ra_ptr = 0;
- b = block;
- for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {
- /*
- * Terminate if we reach the end of the
- * directory and must wrap, or if our
- * search has finished at this block.
- */
- if (b >= nblocks || (num && block == start)) {
- bh_use[ra_max] = NULL;
- break;
- }
- num++;
- bh = ext4_getblk(NULL, dir, b++, 0);
- if (IS_ERR(bh)) {
- if (ra_max == 0) {
- ret = bh;
- goto cleanup_and_exit;
- }
- break;
- }
- bh_use[ra_max] = bh;
- if (bh)
- ll_rw_block(REQ_OP_READ,
- REQ_META | REQ_PRIO,
- 1, &bh);
+ if (block < start)
+ ra_max = start - block;
+ else
+ ra_max = nblocks - block;
+ ra_max = min(ra_max, ARRAY_SIZE(bh_use));
+ retval = ext4_bread_batch(dir, block, ra_max,
+ false /* wait */, bh_use);
+ if (retval) {
+ ret = ERR_PTR(retval);
+ ra_max = 0;
+ goto cleanup_and_exit;
}
}
if ((bh = bh_use[ra_ptr++]) == NULL)
@@ -2395,19 +2380,22 @@ out:
}
/*
- * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2,
- * since this indicates that nlinks count was previously 1.
+ * Set directory link count to 1 if nlinks > EXT4_LINK_MAX, or if nlinks == 2
+ * since this indicates that nlinks count was previously 1 to avoid overflowing
+ * the 16-bit i_links_count field on disk. Directories with i_nlink == 1 mean
+ * that subdirectory link counts are not being maintained accurately.
+ *
+ * The caller has already checked for i_nlink overflow in case the DIR_LINK
+ * feature is not enabled and returned -EMLINK. The is_dx() check is a proxy
+ * for checking S_ISDIR(inode) (since the INODE_INDEX feature will not be set
+ * on regular files) and to avoid creating huge/slow non-HTREE directories.
*/
static void ext4_inc_count(handle_t *handle, struct inode *inode)
{
inc_nlink(inode);
- if (is_dx(inode) && inode->i_nlink > 1) {
- /* limit is 16-bit i_links_count */
- if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) {
- set_nlink(inode, 1);
- ext4_set_feature_dir_nlink(inode->i_sb);
- }
- }
+ if (is_dx(inode) &&
+ (inode->i_nlink > EXT4_LINK_MAX || inode->i_nlink == 2))
+ set_nlink(inode, 1);
}
/*
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index c3ed902..035cd3f 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1927,7 +1927,8 @@ retry:
n_desc_blocks = o_desc_blocks +
le16_to_cpu(es->s_reserved_gdt_blocks);
n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK(sb);
- n_blocks_count = n_group * EXT4_BLOCKS_PER_GROUP(sb);
+ n_blocks_count = (ext4_fsblk_t)n_group *
+ EXT4_BLOCKS_PER_GROUP(sb);
n_group--; /* set to last group number */
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 0886fe8..d61a70e2 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -978,8 +978,6 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
ei->i_es_shk_nr = 0;
ei->i_es_shrink_lblk = 0;
ei->i_reserved_data_blocks = 0;
- ei->i_reserved_meta_blocks = 0;
- ei->i_allocated_meta_blocks = 0;
ei->i_da_metadata_calc_len = 0;
ei->i_da_metadata_calc_last_lblock = 0;
spin_lock_init(&(ei->i_block_reservation_lock));
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index cff4f41..82a5af9 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -317,28 +317,41 @@ static void ext4_xattr_inode_set_hash(struct inode *ea_inode, u32 hash)
*/
static int ext4_xattr_inode_read(struct inode *ea_inode, void *buf, size_t size)
{
- unsigned long block = 0;
- struct buffer_head *bh;
- int blocksize = ea_inode->i_sb->s_blocksize;
- size_t csize, copied = 0;
- void *copy_pos = buf;
-
- while (copied < size) {
- csize = (size - copied) > blocksize ? blocksize : size - copied;
- bh = ext4_bread(NULL, ea_inode, block, 0);
- if (IS_ERR(bh))
- return PTR_ERR(bh);
- if (!bh)
- return -EFSCORRUPTED;
+ int blocksize = 1 << ea_inode->i_blkbits;
+ int bh_count = (size + blocksize - 1) >> ea_inode->i_blkbits;
+ int tail_size = (size % blocksize) ?: blocksize;
+ struct buffer_head *bhs_inline[8];
+ struct buffer_head **bhs = bhs_inline;
+ int i, ret;
+
+ if (bh_count > ARRAY_SIZE(bhs_inline)) {
+ bhs = kmalloc_array(bh_count, sizeof(*bhs), GFP_NOFS);
+ if (!bhs)
+ return -ENOMEM;
+ }
- memcpy(copy_pos, bh->b_data, csize);
- brelse(bh);
+ ret = ext4_bread_batch(ea_inode, 0 /* block */, bh_count,
+ true /* wait */, bhs);
+ if (ret)
+ goto free_bhs;
- copy_pos += csize;
- block += 1;
- copied += csize;
+ for (i = 0; i < bh_count; i++) {
+ /* There shouldn't be any holes in ea_inode. */
+ if (!bhs[i]) {
+ ret = -EFSCORRUPTED;
+ goto put_bhs;
+ }
+ memcpy((char *)buf + blocksize * i, bhs[i]->b_data,
+ i < bh_count - 1 ? blocksize : tail_size);
}
- return 0;
+ ret = 0;
+put_bhs:
+ for (i = 0; i < bh_count; i++)
+ brelse(bhs[i]);
+free_bhs:
+ if (bhs != bhs_inline)
+ kfree(bhs);
+ return ret;
}
static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
@@ -451,6 +464,7 @@ ext4_xattr_inode_get(struct inode *inode, struct ext4_xattr_entry *entry,
}
/* Do not add ea_inode to the cache. */
ea_inode_cache = NULL;
+ err = 0;
} else if (err)
goto out;
@@ -1815,9 +1829,6 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
ea_bdebug(bs->bh, "modifying in-place");
error = ext4_xattr_set_entry(i, s, handle, inode,
true /* is_block */);
- if (!error)
- ext4_xattr_block_cache_insert(ea_block_cache,
- bs->bh);
ext4_xattr_block_csum_set(inode, bs->bh);
unlock_buffer(bs->bh);
if (error == -EFSCORRUPTED)
@@ -1973,6 +1984,7 @@ inserted:
} else if (bs->bh && s->base == bs->bh->b_data) {
/* We were modifying this block in-place. */
ea_bdebug(bs->bh, "keeping this block");
+ ext4_xattr_block_cache_insert(ea_block_cache, bs->bh);
new_bh = bs->bh;
get_bh(new_bh);
} else {
@@ -2625,23 +2637,21 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
struct ext4_inode *raw_inode, handle_t *handle)
{
struct ext4_xattr_ibody_header *header;
- struct buffer_head *bh = NULL;
+ struct buffer_head *bh;
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ static unsigned int mnt_count;
size_t min_offs;
size_t ifree, bfree;
int total_ino;
void *base, *end;
int error = 0, tried_min_extra_isize = 0;
- int s_min_extra_isize = le16_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize);
+ int s_min_extra_isize = le16_to_cpu(sbi->s_es->s_min_extra_isize);
int isize_diff; /* How much do we need to grow i_extra_isize */
- int no_expand;
-
- if (ext4_write_trylock_xattr(inode, &no_expand) == 0)
- return 0;
retry:
isize_diff = new_extra_isize - EXT4_I(inode)->i_extra_isize;
if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
- goto out;
+ return 0;
header = IHDR(inode, raw_inode);
@@ -2676,6 +2686,7 @@ retry:
EXT4_ERROR_INODE(inode, "bad block %llu",
EXT4_I(inode)->i_file_acl);
error = -EFSCORRUPTED;
+ brelse(bh);
goto cleanup;
}
base = BHDR(bh);
@@ -2683,11 +2694,11 @@ retry:
min_offs = end - base;
bfree = ext4_xattr_free_space(BFIRST(bh), &min_offs, base,
NULL);
+ brelse(bh);
if (bfree + ifree < isize_diff) {
if (!tried_min_extra_isize && s_min_extra_isize) {
tried_min_extra_isize++;
new_extra_isize = s_min_extra_isize;
- brelse(bh);
goto retry;
}
error = -ENOSPC;
@@ -2705,7 +2716,6 @@ retry:
s_min_extra_isize) {
tried_min_extra_isize++;
new_extra_isize = s_min_extra_isize;
- brelse(bh);
goto retry;
}
goto cleanup;
@@ -2717,18 +2727,13 @@ shift:
EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize,
(void *)header, total_ino);
EXT4_I(inode)->i_extra_isize = new_extra_isize;
- brelse(bh);
-out:
- ext4_write_unlock_xattr(inode, &no_expand);
- return 0;
cleanup:
- brelse(bh);
- /*
- * Inode size expansion failed; don't try again
- */
- no_expand = 1;
- ext4_write_unlock_xattr(inode, &no_expand);
+ if (error && (mnt_count != le16_to_cpu(sbi->s_es->s_mnt_count))) {
+ ext4_warning(inode->i_sb, "Unable to expand inode %lu. Delete some EAs or run e2fsck.",
+ inode->i_ino);
+ mnt_count = le16_to_cpu(sbi->s_es->s_mnt_count);
+ }
return error;
}
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 50566acb..e9bea90 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -660,9 +660,6 @@ int nfs4_detect_session_trunking(struct nfs_client *clp,
if (!nfs4_check_server_scope(clp->cl_serverscope, res->server_scope))
goto out_err;
- /* Session trunking passed, add the xprt */
- rpc_clnt_xprt_switch_add_xprt(clp->cl_rpcclient, xprt);
-
pr_info("NFS: %s: Session trunking succeeded for %s\n",
clp->cl_hostname,
xprt->address_strings[RPC_DISPLAY_ADDR]);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 18ca687..ffd2e71 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -7461,7 +7461,7 @@ static void nfs4_exchange_id_done(struct rpc_task *task, void *data)
cdata->res.server_scope = NULL;
}
/* Save the EXCHANGE_ID verifier session trunk tests */
- memcpy(clp->cl_confirm.data, cdata->args.verifier->data,
+ memcpy(clp->cl_confirm.data, cdata->args.verifier.data,
sizeof(clp->cl_confirm.data));
}
out:
@@ -7474,10 +7474,6 @@ static void nfs4_exchange_id_release(void *data)
struct nfs41_exchange_id_data *cdata =
(struct nfs41_exchange_id_data *)data;
- if (cdata->xprt) {
- xprt_put(cdata->xprt);
- rpc_clnt_xprt_switch_put(cdata->args.client->cl_rpcclient);
- }
nfs_put_client(cdata->args.client);
kfree(cdata->res.impl_id);
kfree(cdata->res.server_scope);
@@ -7498,7 +7494,6 @@ static const struct rpc_call_ops nfs4_exchange_id_call_ops = {
static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
u32 sp4_how, struct rpc_xprt *xprt)
{
- nfs4_verifier verifier;
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID],
.rpc_cred = cred,
@@ -7507,7 +7502,7 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
.rpc_client = clp->cl_rpcclient,
.callback_ops = &nfs4_exchange_id_call_ops,
.rpc_message = &msg,
- .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT,
+ .flags = RPC_TASK_TIMEOUT,
};
struct nfs41_exchange_id_data *calldata;
struct rpc_task *task;
@@ -7522,8 +7517,7 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
return -ENOMEM;
}
- if (!xprt)
- nfs4_init_boot_verifier(clp, &verifier);
+ nfs4_init_boot_verifier(clp, &calldata->args.verifier);
status = nfs4_init_uniform_client_string(clp);
if (status)
@@ -7562,11 +7556,9 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
if (xprt) {
calldata->xprt = xprt;
task_setup_data.rpc_xprt = xprt;
- task_setup_data.flags =
- RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC;
- calldata->args.verifier = &clp->cl_confirm;
- } else {
- calldata->args.verifier = &verifier;
+ task_setup_data.flags |= RPC_TASK_SOFTCONN;
+ memcpy(calldata->args.verifier.data, clp->cl_confirm.data,
+ sizeof(calldata->args.verifier.data));
}
calldata->args.client = clp;
#ifdef CONFIG_NFS_V4_1_MIGRATION
@@ -7585,12 +7577,7 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
if (IS_ERR(task))
return PTR_ERR(task);
- if (!xprt) {
- status = rpc_wait_for_completion_task(task);
- if (!status)
- status = calldata->rpc_status;
- } else /* session trunking test */
- status = calldata->rpc_status;
+ status = calldata->rpc_status;
rpc_put_task(task);
out:
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index fa3eb36..37c8af0 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1785,7 +1785,7 @@ static void encode_exchange_id(struct xdr_stream *xdr,
int len = 0;
encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr);
- encode_nfs4_verifier(xdr, args->verifier);
+ encode_nfs4_verifier(xdr, &args->verifier);
encode_string(xdr, strlen(args->client->cl_owner_id),
args->client->cl_owner_id);
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
index dc22ba8..e50a387 100644
--- a/fs/ocfs2/acl.c
+++ b/fs/ocfs2/acl.c
@@ -240,18 +240,6 @@ int ocfs2_set_acl(handle_t *handle,
switch (type) {
case ACL_TYPE_ACCESS:
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
- if (acl) {
- umode_t mode;
-
- ret = posix_acl_update_mode(inode, &mode, &acl);
- if (ret)
- return ret;
-
- ret = ocfs2_acl_set_mode(inode, di_bh,
- handle, mode);
- if (ret)
- return ret;
- }
break;
case ACL_TYPE_DEFAULT:
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
@@ -289,7 +277,19 @@ int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type)
had_lock = ocfs2_inode_lock_tracker(inode, &bh, 1, &oh);
if (had_lock < 0)
return had_lock;
+ if (type == ACL_TYPE_ACCESS && acl) {
+ umode_t mode;
+
+ status = posix_acl_update_mode(inode, &mode, &acl);
+ if (status)
+ goto unlock;
+
+ status = ocfs2_acl_set_mode(inode, bh, NULL, mode);
+ if (status)
+ goto unlock;
+ }
status = ocfs2_set_acl(NULL, inode, bh, type, acl, NULL, NULL);
+unlock:
ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock);
brelse(bh);
return status;
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index cadcd12..06ea26b 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -854,6 +854,9 @@ wakeup:
__wake_up_locked_key(&ctx->fault_wqh, TASK_NORMAL, &range);
spin_unlock(&ctx->fault_pending_wqh.lock);
+ /* Flush pending events that may still wait on event_wqh */
+ wake_up_all(&ctx->event_wqh);
+
wake_up_poll(&ctx->fd_wqh, POLLHUP);
userfaultfd_ctx_put(ctx);
return 0;
@@ -1643,6 +1646,8 @@ static int userfaultfd_zeropage(struct userfaultfd_ctx *ctx,
ret = mfill_zeropage(ctx->mm, uffdio_zeropage.range.start,
uffdio_zeropage.range.len);
mmput(ctx->mm);
+ } else {
+ return -ENOSPC;
}
if (unlikely(put_user(ret, &user_uffdio_zeropage->zeropage)))
return -EFAULT;
OpenPOWER on IntegriCloud