diff options
Diffstat (limited to 'fs')
115 files changed, 1491 insertions, 1247 deletions
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index 2e38f9a5b472..be35d05a4d0e 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -230,7 +230,6 @@ static int v9fs_launder_page(struct page *page) /** * v9fs_direct_IO - 9P address space operation for direct I/O - * @rw: direction (read or write) * @iocb: target I/O control block * @iov: array of vectors that define I/O buffer * @pos: offset in file to begin the operation @@ -248,12 +247,12 @@ static int v9fs_launder_page(struct page *page) * */ static ssize_t -v9fs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos) +v9fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t pos) { struct file *file = iocb->ki_filp; ssize_t n; int err = 0; - if (rw & WRITE) { + if (iov_iter_rw(iter) == WRITE) { n = p9_client_write(file->private_data, pos, iter, &err); if (n) { struct inode *inode = file_inode(file); diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index d7fcb775311e..2a9dd37dc426 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -404,21 +404,16 @@ static ssize_t v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; - ssize_t retval = 0; - loff_t origin = iocb->ki_pos; - size_t count = iov_iter_count(from); + ssize_t retval; + loff_t origin; int err = 0; - retval = generic_write_checks(file, &origin, &count, 0); - if (retval) + retval = generic_write_checks(iocb, from); + if (retval <= 0) return retval; - iov_iter_truncate(from, count); - - if (!count) - return 0; - - retval = p9_client_write(file->private_data, origin, from, &err); + origin = iocb->ki_pos; + retval = p9_client_write(file->private_data, iocb->ki_pos, from, &err); if (retval > 0) { struct inode *inode = file_inode(file); loff_t i_size; @@ -428,12 +423,11 @@ v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (inode->i_mapping && inode->i_mapping->nrpages) invalidate_inode_pages2_range(inode->i_mapping, pg_start, pg_end); - origin += retval; + iocb->ki_pos += retval; i_size = i_size_read(inode); - iocb->ki_pos = origin; - if (origin > i_size) { - inode_add_bytes(inode, origin - i_size); - i_size_write(inode, origin); + if (iocb->ki_pos > i_size) { + inode_add_bytes(inode, iocb->ki_pos - i_size); + i_size_write(inode, iocb->ki_pos); } return retval; } diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c index f2ba88ab4aed..82d14cdf70f9 100644 --- a/fs/adfs/dir_fplus.c +++ b/fs/adfs/dir_fplus.c @@ -61,6 +61,7 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct kcalloc(size, sizeof(struct buffer_head *), GFP_KERNEL); if (!bh_fplus) { + ret = -ENOMEM; adfs_error(sb, "not enough memory for" " dir object %X (%d blocks)", id, size); goto out; diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 9852bdf34d76..a19c31d3f369 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -316,7 +316,7 @@ static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_di dm = kmalloc(nzones * sizeof(*dm), GFP_KERNEL); if (dm == NULL) { adfs_error(sb, "not enough memory"); - return NULL; + return ERR_PTR(-ENOMEM); } for (zone = 0; zone < nzones; zone++, map_addr++) { @@ -349,7 +349,7 @@ error_free: brelse(dm[zone].dm_bh); kfree(dm); - return NULL; + return ERR_PTR(-EIO); } static inline unsigned long adfs_discsize(struct adfs_discrecord *dr, int block_bits) @@ -370,6 +370,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) unsigned char *b_data; struct adfs_sb_info *asb; struct inode *root; + int ret = -EINVAL; sb->s_flags |= MS_NODIRATIME; @@ -391,6 +392,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) sb_set_blocksize(sb, BLOCK_SIZE); if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) { adfs_error(sb, "unable to read superblock"); + ret = -EIO; goto error; } @@ -400,6 +402,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) if (!silent) printk("VFS: Can't find an adfs filesystem on dev " "%s.\n", sb->s_id); + ret = -EINVAL; goto error_free_bh; } @@ -412,6 +415,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) if (!silent) printk("VPS: Can't find an adfs filesystem on dev " "%s.\n", sb->s_id); + ret = -EINVAL; goto error_free_bh; } @@ -421,11 +425,13 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) if (!bh) { adfs_error(sb, "couldn't read superblock on " "2nd try."); + ret = -EIO; goto error; } b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize); if (adfs_checkbblk(b_data)) { adfs_error(sb, "disc record mismatch, very weird!"); + ret = -EINVAL; goto error_free_bh; } dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET); @@ -433,6 +439,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) if (!silent) printk(KERN_ERR "VFS: Unsupported blocksize on dev " "%s.\n", sb->s_id); + ret = -EINVAL; goto error; } @@ -447,10 +454,12 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) asb->s_size = adfs_discsize(dr, sb->s_blocksize_bits); asb->s_version = dr->format_version; asb->s_log2sharesize = dr->log2sharesize; - + asb->s_map = adfs_read_map(sb, dr); - if (!asb->s_map) + if (IS_ERR(asb->s_map)) { + ret = PTR_ERR(asb->s_map); goto error_free_bh; + } brelse(bh); @@ -499,6 +508,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) brelse(asb->s_map[i].dm_bh); kfree(asb->s_map); adfs_error(sb, "get root inode failed\n"); + ret = -EIO; goto error; } return 0; @@ -508,7 +518,7 @@ error_free_bh: error: sb->s_fs_info = NULL; kfree(asb); - return -EINVAL; + return ret; } static struct dentry *adfs_mount(struct file_system_type *fs_type, diff --git a/fs/affs/affs.h b/fs/affs/affs.h index c8764bd7497d..cffe8370fb44 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -106,18 +106,22 @@ struct affs_sb_info { spinlock_t work_lock; /* protects sb_work and work_queued */ }; -#define SF_INTL 0x0001 /* International filesystem. */ -#define SF_BM_VALID 0x0002 /* Bitmap is valid. */ -#define SF_IMMUTABLE 0x0004 /* Protection bits cannot be changed */ -#define SF_QUIET 0x0008 /* chmod errors will be not reported */ -#define SF_SETUID 0x0010 /* Ignore Amiga uid */ -#define SF_SETGID 0x0020 /* Ignore Amiga gid */ -#define SF_SETMODE 0x0040 /* Ignore Amiga protection bits */ -#define SF_MUFS 0x0100 /* Use MUFS uid/gid mapping */ -#define SF_OFS 0x0200 /* Old filesystem */ -#define SF_PREFIX 0x0400 /* Buffer for prefix is allocated */ -#define SF_VERBOSE 0x0800 /* Talk about fs when mounting */ -#define SF_NO_TRUNCATE 0x1000 /* Don't truncate filenames */ +#define AFFS_MOUNT_SF_INTL 0x0001 /* International filesystem. */ +#define AFFS_MOUNT_SF_BM_VALID 0x0002 /* Bitmap is valid. */ +#define AFFS_MOUNT_SF_IMMUTABLE 0x0004 /* Protection bits cannot be changed */ +#define AFFS_MOUNT_SF_QUIET 0x0008 /* chmod errors will be not reported */ +#define AFFS_MOUNT_SF_SETUID 0x0010 /* Ignore Amiga uid */ +#define AFFS_MOUNT_SF_SETGID 0x0020 /* Ignore Amiga gid */ +#define AFFS_MOUNT_SF_SETMODE 0x0040 /* Ignore Amiga protection bits */ +#define AFFS_MOUNT_SF_MUFS 0x0100 /* Use MUFS uid/gid mapping */ +#define AFFS_MOUNT_SF_OFS 0x0200 /* Old filesystem */ +#define AFFS_MOUNT_SF_PREFIX 0x0400 /* Buffer for prefix is allocated */ +#define AFFS_MOUNT_SF_VERBOSE 0x0800 /* Talk about fs when mounting */ +#define AFFS_MOUNT_SF_NO_TRUNCATE 0x1000 /* Don't truncate filenames */ + +#define affs_clear_opt(o, opt) (o &= ~AFFS_MOUNT_##opt) +#define affs_set_opt(o, opt) (o |= AFFS_MOUNT_##opt) +#define affs_test_opt(o, opt) ((o) & AFFS_MOUNT_##opt) /* short cut to get to the affs specific sb data */ static inline struct affs_sb_info *AFFS_SB(struct super_block *sb) diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 388da1ea815d..5022ac96aa40 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -472,7 +472,8 @@ bool affs_nofilenametruncate(const struct dentry *dentry) { struct inode *inode = dentry->d_inode; - return AFFS_SB(inode->i_sb)->s_flags & SF_NO_TRUNCATE; + + return affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_NO_TRUNCATE); } diff --git a/fs/affs/file.c b/fs/affs/file.c index 7c1a3d4c19c2..659c579c4588 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -389,8 +389,7 @@ static void affs_write_failed(struct address_space *mapping, loff_t to) } static ssize_t -affs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) +affs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -398,15 +397,15 @@ affs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, size_t count = iov_iter_count(iter); ssize_t ret; - if (rw == WRITE) { + if (iov_iter_rw(iter) == WRITE) { loff_t size = offset + count; if (AFFS_I(inode)->mmu_private < size) return 0; } - ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, affs_get_block); - if (ret < 0 && (rw & WRITE)) + ret = blockdev_direct_IO(iocb, inode, iter, offset, affs_get_block); + if (ret < 0 && iov_iter_rw(iter) == WRITE) affs_write_failed(mapping, offset + count); return ret; } @@ -915,7 +914,7 @@ affs_truncate(struct inode *inode) if (inode->i_size) { AFFS_I(inode)->i_blkcnt = last_blk + 1; AFFS_I(inode)->i_extcnt = ext + 1; - if (AFFS_SB(sb)->s_flags & SF_OFS) { + if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS)) { struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0); u32 tmp; if (IS_ERR(bh)) { diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 6f34510449e8..9628003ccd2f 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -66,23 +66,23 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) AFFS_I(inode)->i_lastalloc = 0; AFFS_I(inode)->i_pa_cnt = 0; - if (sbi->s_flags & SF_SETMODE) + if (affs_test_opt(sbi->s_flags, SF_SETMODE)) inode->i_mode = sbi->s_mode; else inode->i_mode = prot_to_mode(prot); id = be16_to_cpu(tail->uid); - if (id == 0 || sbi->s_flags & SF_SETUID) + if (id == 0 || affs_test_opt(sbi->s_flags, SF_SETUID)) inode->i_uid = sbi->s_uid; - else if (id == 0xFFFF && sbi->s_flags & SF_MUFS) + else if (id == 0xFFFF && affs_test_opt(sbi->s_flags, SF_MUFS)) i_uid_write(inode, 0); else i_uid_write(inode, id); id = be16_to_cpu(tail->gid); - if (id == 0 || sbi->s_flags & SF_SETGID) + if (id == 0 || affs_test_opt(sbi->s_flags, SF_SETGID)) inode->i_gid = sbi->s_gid; - else if (id == 0xFFFF && sbi->s_flags & SF_MUFS) + else if (id == 0xFFFF && affs_test_opt(sbi->s_flags, SF_MUFS)) i_gid_write(inode, 0); else i_gid_write(inode, id); @@ -94,7 +94,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) /* fall through */ case ST_USERDIR: if (be32_to_cpu(tail->stype) == ST_USERDIR || - sbi->s_flags & SF_SETMODE) { + affs_test_opt(sbi->s_flags, SF_SETMODE)) { if (inode->i_mode & S_IRUSR) inode->i_mode |= S_IXUSR; if (inode->i_mode & S_IRGRP) @@ -133,7 +133,8 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) } if (tail->link_chain) set_nlink(inode, 2); - inode->i_mapping->a_ops = (sbi->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops; + inode->i_mapping->a_ops = affs_test_opt(sbi->s_flags, SF_OFS) ? + &affs_aops_ofs : &affs_aops; inode->i_op = &affs_file_inode_operations; inode->i_fop = &affs_file_operations; break; @@ -190,15 +191,15 @@ affs_write_inode(struct inode *inode, struct writeback_control *wbc) if (!(inode->i_ino == AFFS_SB(sb)->s_root_block)) { uid = i_uid_read(inode); gid = i_gid_read(inode); - if (AFFS_SB(sb)->s_flags & SF_MUFS) { + if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_MUFS)) { if (uid == 0 || uid == 0xFFFF) uid = uid ^ ~0; if (gid == 0 || gid == 0xFFFF) gid = gid ^ ~0; } - if (!(AFFS_SB(sb)->s_flags & SF_SETUID)) + if (!affs_test_opt(AFFS_SB(sb)->s_flags, SF_SETUID)) tail->uid = cpu_to_be16(uid); - if (!(AFFS_SB(sb)->s_flags & SF_SETGID)) + if (!affs_test_opt(AFFS_SB(sb)->s_flags, SF_SETGID)) tail->gid = cpu_to_be16(gid); } } @@ -221,11 +222,14 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr) if (error) goto out; - if (((attr->ia_valid & ATTR_UID) && (AFFS_SB(inode->i_sb)->s_flags & SF_SETUID)) || - ((attr->ia_valid & ATTR_GID) && (AFFS_SB(inode->i_sb)->s_flags & SF_SETGID)) || + if (((attr->ia_valid & ATTR_UID) && + affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_SETUID)) || + ((attr->ia_valid & ATTR_GID) && + affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_SETGID)) || ((attr->ia_valid & ATTR_MODE) && - (AFFS_SB(inode->i_sb)->s_flags & (SF_SETMODE | SF_IMMUTABLE)))) { - if (!(AFFS_SB(inode->i_sb)->s_flags & SF_QUIET)) + (AFFS_SB(inode->i_sb)->s_flags & + (AFFS_MOUNT_SF_SETMODE | AFFS_MOUNT_SF_IMMUTABLE)))) { + if (!affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_QUIET)) error = -EPERM; goto out; } diff --git a/fs/affs/namei.c b/fs/affs/namei.c index ffb7bd82c2a5..ec8ca0efb960 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -53,7 +53,8 @@ affs_intl_toupper(int ch) static inline toupper_t affs_get_toupper(struct super_block *sb) { - return AFFS_SB(sb)->s_flags & SF_INTL ? affs_intl_toupper : affs_toupper; + return affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL) ? + affs_intl_toupper : affs_toupper; } /* @@ -275,7 +276,8 @@ affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) inode->i_op = &affs_file_inode_operations; inode->i_fop = &affs_file_operations; - inode->i_mapping->a_ops = (AFFS_SB(sb)->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops; + inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ? + &affs_aops_ofs : &affs_aops; error = affs_add_entry(dir, inode, dentry, ST_FILE); if (error) { clear_nlink(inode); diff --git a/fs/affs/super.c b/fs/affs/super.c index 4cf0e9113fb6..3f89c9e05b40 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -227,22 +227,22 @@ parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved, if (match_octal(&args[0], &option)) return 0; *mode = option & 0777; - *mount_opts |= SF_SETMODE; + affs_set_opt(*mount_opts, SF_SETMODE); break; case Opt_mufs: - *mount_opts |= SF_MUFS; + affs_set_opt(*mount_opts, SF_MUFS); break; case Opt_notruncate: - *mount_opts |= SF_NO_TRUNCATE; + affs_set_opt(*mount_opts, SF_NO_TRUNCATE); break; case Opt_prefix: *prefix = match_strdup(&args[0]); if (!*prefix) return 0; - *mount_opts |= SF_PREFIX; + affs_set_opt(*mount_opts, SF_PREFIX); break; case Opt_protect: - *mount_opts |= SF_IMMUTABLE; + affs_set_opt(*mount_opts, SF_IMMUTABLE); break; case Opt_reserved: if (match_int(&args[0], reserved)) @@ -258,7 +258,7 @@ parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved, *gid = make_kgid(current_user_ns(), option); if (!gid_valid(*gid)) return 0; - *mount_opts |= SF_SETGID; + affs_set_opt(*mount_opts, SF_SETGID); break; case Opt_setuid: if (match_int(&args[0], &option)) @@ -266,10 +266,10 @@ parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved, *uid = make_kuid(current_user_ns(), option); if (!uid_valid(*uid)) return 0; - *mount_opts |= SF_SETUID; + affs_set_opt(*mount_opts, SF_SETUID); break; case Opt_verbose: - *mount_opts |= SF_VERBOSE; + affs_set_opt(*mount_opts, SF_VERBOSE); break; case Opt_volume: { char *vol = match_strdup(&args[0]); @@ -435,30 +435,31 @@ got_root: case MUFS_FS: case MUFS_INTLFFS: case MUFS_DCFFS: - sbi->s_flags |= SF_MUFS; + affs_set_opt(sbi->s_flags, SF_MUFS); /* fall thru */ case FS_INTLFFS: case FS_DCFFS: - sbi->s_flags |= SF_INTL; + affs_set_opt(sbi->s_flags, SF_INTL); break; case MUFS_FFS: - sbi->s_flags |= SF_MUFS; + affs_set_opt(sbi->s_flags, SF_MUFS); break; case FS_FFS: break; case MUFS_OFS: - sbi->s_flags |= SF_MUFS; + affs_set_opt(sbi->s_flags, SF_MUFS); /* fall thru */ case FS_OFS: - sbi->s_flags |= SF_OFS; + affs_set_opt(sbi->s_flags, SF_OFS); sb->s_flags |= MS_NOEXEC; break; case MUFS_DCOFS: case MUFS_INTLOFS: - sbi->s_flags |= SF_MUFS; + affs_set_opt(sbi->s_flags, SF_MUFS); case FS_DCOFS: case FS_INTLOFS: - sbi->s_flags |= SF_INTL | SF_OFS; + affs_set_opt(sbi->s_flags, SF_INTL); + affs_set_opt(sbi->s_flags, SF_OFS); sb->s_flags |= MS_NOEXEC; break; default: @@ -467,7 +468,7 @@ got_root: return -EINVAL; } - if (mount_flags & SF_VERBOSE) { + if (affs_test_opt(mount_flags, SF_VERBOSE)) { u8 len = AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0]; pr_notice("Mounting volume \"%.*s\": Type=%.3s\\%c, Blocksize=%d\n", len > 31 ? 31 : len, @@ -478,7 +479,7 @@ got_root: sb->s_flags |= MS_NODEV | MS_NOSUID; sbi->s_data_blksize = sb->s_blocksize; - if (sbi->s_flags & SF_OFS) + if (affs_test_opt(sbi->s_flags, SF_OFS)) sbi->s_data_blksize -= 24; tmp_flags = sb->s_flags; @@ -493,7 +494,7 @@ got_root: if (IS_ERR(root_inode)) return PTR_ERR(root_inode); - if (AFFS_SB(sb)->s_flags & SF_INTL) + if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL)) sb->s_d_op = &affs_intl_dentry_operations; else sb->s_d_op = &affs_dentry_operations; @@ -520,10 +521,14 @@ affs_remount(struct super_block *sb, int *flags, char *data) int root_block; unsigned long mount_flags; int res = 0; - char *new_opts = kstrdup(data, GFP_KERNEL); + char *new_opts; char volume[32]; char *prefix = NULL; + new_opts = kstrdup(data, GFP_KERNEL); + if (!new_opts) + return -ENOMEM; + pr_debug("%s(flags=0x%x,opts=\"%s\")\n", __func__, *flags, data); sync_filesystem(sb); @@ -77,6 +77,11 @@ struct kioctx_cpu { unsigned reqs_available; }; +struct ctx_rq_wait { + struct completion comp; + atomic_t count; +}; + struct kioctx { struct percpu_ref users; atomic_t dead; @@ -115,7 +120,7 @@ struct kioctx { /* * signals when all in-flight requests are done */ - struct completion *requests_done; + struct ctx_rq_wait *rq_wait; struct { /* @@ -572,8 +577,8 @@ static void free_ioctx_reqs(struct percpu_ref *ref) struct kioctx *ctx = container_of(ref, struct kioctx, reqs); /* At this point we know that there are no any in-flight requests */ - if (ctx->requests_done) - complete(ctx->requests_done); + if (ctx->rq_wait && atomic_dec_and_test(&ctx->rq_wait->count)) + complete(&ctx->rq_wait->comp); INIT_WORK(&ctx->free_work, free_ioctx); schedule_work(&ctx->free_work); @@ -783,7 +788,7 @@ err: * the rapid destruction of the kioctx. */ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx, - struct completion *requests_done) + struct ctx_rq_wait *wait) { struct kioctx_table *table; @@ -813,7 +818,7 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx, if (ctx->mmap_size) vm_munmap(ctx->mmap_base, ctx->mmap_size); - ctx->requests_done = requests_done; + ctx->rq_wait = wait; percpu_ref_kill(&ctx->users); return 0; } @@ -829,18 +834,24 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx, void exit_aio(struct mm_struct *mm) { struct kioctx_table *table = rcu_dereference_raw(mm->ioctx_table); - int i; + struct ctx_rq_wait wait; + int i, skipped; if (!table) return; + atomic_set(&wait.count, table->nr); + init_completion(&wait.comp); + + skipped = 0; for (i = 0; i < table->nr; ++i) { struct kioctx *ctx = table->table[i]; - struct completion requests_done = - COMPLETION_INITIALIZER_ONSTACK(requests_done); - if (!ctx) + if (!ctx) { + skipped++; continue; + } + /* * We don't need to bother with munmap() here - exit_mmap(mm) * is coming and it'll unmap everything. And we simply can't, @@ -849,10 +860,12 @@ void exit_aio(struct mm_struct *mm) * that it needs to unmap the area, just set it to 0. */ ctx->mmap_size = 0; - kill_ioctx(mm, ctx, &requests_done); + kill_ioctx(mm, ctx, &wait); + } + if (!atomic_sub_and_test(skipped, &wait.count)) { /* Wait until all IO for the context are done. */ - wait_for_completion(&requests_done); + wait_for_completion(&wait.comp); } RCU_INIT_POINTER(mm->ioctx_table, NULL); @@ -1331,15 +1344,17 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx) { struct kioctx *ioctx = lookup_ioctx(ctx); if (likely(NULL != ioctx)) { - struct completion requests_done = - COMPLETION_INITIALIZER_ONSTACK(requests_done); + struct ctx_rq_wait wait; int ret; + init_completion(&wait.comp); + atomic_set(&wait.count, 1); + /* Pass requests_done to kill_ioctx() where it can be set * in a thread-safe way. If we try to set it here then we have * a race condition if two io_destroy() called simultaneously. */ - ret = kill_ioctx(current->mm, ioctx, &requests_done); + ret = kill_ioctx(current->mm, ioctx, &wait); percpu_ref_put(&ioctx->users); /* Wait until all IO for the context are done. Otherwise kernel @@ -1347,7 +1362,7 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx) * is destroyed. */ if (!ret) - wait_for_completion(&requests_done); + wait_for_completion(&wait.comp); return ret; } @@ -1502,7 +1517,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, } req->common.ki_pos = iocb->aio_offset; req->common.ki_complete = aio_complete; - req->common.ki_flags = 0; + req->common.ki_flags = iocb_flags(req->common.ki_filp); if (iocb->aio_flags & IOCB_FLAG_RESFD) { /* diff --git a/fs/befs/befs.h b/fs/befs/befs.h index 3a7813ab8c95..1fead8d56a98 100644 --- a/fs/befs/befs.h +++ b/fs/befs/befs.h @@ -19,16 +19,16 @@ typedef u64 befs_blocknr_t; * BeFS in memory structures */ -typedef struct befs_mount_options { +struct befs_mount_options { kgid_t gid; kuid_t uid; int use_gid; int use_uid; int debug; char *iocharset; -} befs_mount_options; +}; -typedef struct befs_sb_info { +struct befs_sb_info { u32 magic1; u32 block_size; u32 block_shift; @@ -52,12 +52,11 @@ typedef struct befs_sb_info { befs_inode_addr indices; u32 magic3; - befs_mount_options mount_opts; + struct befs_mount_options mount_opts; struct nls_table *nls; +}; -} befs_sb_info; - -typedef struct befs_inode_info { +struct befs_inode_info { u32 i_flags; u32 i_type; @@ -71,8 +70,7 @@ typedef struct befs_inode_info { } i_data; struct inode vfs_inode; - -} befs_inode_info; +}; enum befs_err { BEFS_OK, @@ -105,13 +103,13 @@ void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *); /* Gets a pointer to the private portion of the super_block * structure from the public part */ -static inline befs_sb_info * +static inline struct befs_sb_info * BEFS_SB(const struct super_block *super) { - return (befs_sb_info *) super->s_fs_info; + return (struct befs_sb_info *) super->s_fs_info; } -static inline befs_inode_info * +static inline struct befs_inode_info * BEFS_I(const struct inode *inode) { return list_entry(inode, struct befs_inode_info, vfs_inode); diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index 1e8e0b8d8836..ebd50718659f 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -168,7 +168,7 @@ befs_count_blocks(struct super_block * sb, befs_data_stream * ds) befs_blocknr_t blocks; befs_blocknr_t datablocks; /* File data blocks */ befs_blocknr_t metablocks; /* FS metadata blocks */ - befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_sb_info *befs_sb = BEFS_SB(sb); befs_debug(sb, "---> %s", __func__); @@ -428,7 +428,7 @@ befs_find_brun_dblindirect(struct super_block *sb, struct buffer_head *indir_block; befs_block_run indir_run; befs_disk_inode_addr *iaddr_array = NULL; - befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_sb_info *befs_sb = BEFS_SB(sb); befs_blocknr_t indir_start_blk = data->max_indirect_range >> befs_sb->block_shift; diff --git a/fs/befs/io.c b/fs/befs/io.c index 0408a3d601d0..7a5b4ec21c56 100644 --- a/fs/befs/io.c +++ b/fs/befs/io.c @@ -28,7 +28,7 @@ befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr) { struct buffer_head *bh = NULL; befs_blocknr_t block = 0; - befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_sb_info *befs_sb = BEFS_SB(sb); befs_debug(sb, "---> Enter %s " "[%u, %hu, %hu]", __func__, iaddr.allocation_group, diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index e089f1985fca..16e0a48bfccd 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -51,7 +51,7 @@ static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, static void befs_put_super(struct super_block *); static int befs_remount(struct super_block *, int *, char *); static int befs_statfs(struct dentry *, struct kstatfs *); -static int parse_options(char *, befs_mount_options *); +static int parse_options(char *, struct befs_mount_options *); static const struct super_operations befs_sops = { .alloc_inode = befs_alloc_inode, /* allocate a new inode */ @@ -304,9 +304,8 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) { struct buffer_head *bh = NULL; befs_inode *raw_inode = NULL; - - befs_sb_info *befs_sb = BEFS_SB(sb); - befs_inode_info *befs_ino = NULL; + struct befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_inode_info *befs_ino = NULL; struct inode *inode; long ret = -EIO; @@ -472,7 +471,7 @@ static void * befs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct super_block *sb = dentry->d_sb; - befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); + struct befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); befs_data_stream *data = &befs_ino->i_data.ds; befs_off_t len = data->size; char *link; @@ -502,7 +501,8 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd) static void * befs_fast_follow_link(struct dentry *dentry, struct nameidata *nd) { - befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); + struct befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); + nd_set_link(nd, befs_ino->i_data.symlink); return NULL; } @@ -669,7 +669,7 @@ static const match_table_t befs_tokens = { }; static int -parse_options(char *options, befs_mount_options * opts) +parse_options(char *options, struct befs_mount_options *opts) { char *p; substring_t args[MAX_OPT_ARGS]; @@ -769,7 +769,7 @@ static int befs_fill_super(struct super_block *sb, void *data, int silent) { struct buffer_head *bh; - befs_sb_info *befs_sb; + struct befs_sb_info *befs_sb; befs_super_block *disk_sb; struct inode *root; long ret = -EINVAL; diff --git a/fs/befs/super.c b/fs/befs/super.c index ca40f828f64d..aeafc4d84278 100644 --- a/fs/befs/super.c +++ b/fs/befs/super.c @@ -24,7 +24,7 @@ int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb) { - befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_sb_info *befs_sb = BEFS_SB(sb); /* Check the byte order of the filesystem */ if (disk_sb->fs_byte_order == BEFS_BYTEORDER_NATIVE_LE) @@ -59,7 +59,7 @@ befs_load_sb(struct super_block *sb, befs_super_block * disk_sb) int befs_check_sb(struct super_block *sb) { - befs_sb_info *befs_sb = BEFS_SB(sb); + struct befs_sb_info *befs_sb = BEFS_SB(sb); /* Check magic headers of super block */ if ((befs_sb->magic1 != BEFS_SUPER_MAGIC1) diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 08063ae0a17c..7a8182770649 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c @@ -86,7 +86,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, inode = new_inode(s); if (!inode) - return -ENOSPC; + return -ENOMEM; mutex_lock(&info->bfs_lock); ino = find_first_zero_bit(info->si_imap, info->si_lasti + 1); if (ino > info->si_lasti) { @@ -293,7 +293,7 @@ static int bfs_add_entry(struct inode *dir, const unsigned char *name, for (block = sblock; block <= eblock; block++) { bh = sb_bread(dir->i_sb, block); if (!bh) - return -ENOSPC; + return -EIO; for (off = 0; off < BFS_BSIZE; off += BFS_DIRENT_SIZE) { de = (struct bfs_dirent *)(bh->b_data + off); if (!de->ino) { diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 97aff2879cda..9dcb05409ba7 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> @@ -521,9 +522,8 @@ static int parse_command(const char __user *buffer, size_t count) static void entry_status(Node *e, char *page) { - char *dp; - char *status = "disabled"; - const char *flags = "flags: "; + char *dp = page; + const char *status = "disabled"; if (test_bit(Enabled, &e->flags)) status = "enabled"; @@ -533,12 +533,10 @@ static void entry_status(Node *e, char *page) return; } - sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter); - dp = page + strlen(page); + dp += sprintf(dp, "%s\ninterpreter %s\n", status, e->interpreter); /* print the special flags */ - sprintf(dp, "%s", flags); - dp += strlen(flags); + dp += sprintf(dp, "flags: "); if (e->flags & MISC_FMT_PRESERVE_ARGV0) *dp++ = 'P'; if (e->flags & MISC_FMT_OPEN_BINARY) @@ -550,21 +548,11 @@ static void entry_status(Node *e, char *page) if (!test_bit(Magic, &e->flags)) { sprintf(dp, "extension .%s\n", e->magic); } else { - int i; - - sprintf(dp, "offset %i\nmagic ", e->offset); - dp = page + strlen(page); - for (i = 0; i < e->size; i++) { - sprintf(dp, "%02x", 0xff & (int) (e->magic[i])); - dp += 2; - } + dp += sprintf(dp, "offset %i\nmagic ", e->offset); + dp = bin2hex(dp, e->magic, e->size); if (e->mask) { - sprintf(dp, "\nmask "); - dp += 6; - for (i = 0; i < e->size; i++) { - sprintf(dp, "%02x", 0xff & (int) (e->mask[i])); - dp += 2; - } + dp += sprintf(dp, "\nmask "); + dp = bin2hex(dp, e->mask, e->size); } *dp++ = '\n'; *dp = '\0'; diff --git a/fs/block_dev.c b/fs/block_dev.c index b5e87896f517..897ee0503932 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -146,15 +146,13 @@ blkdev_get_block(struct inode *inode, sector_t iblock, } static ssize_t -blkdev_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) +blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iter, - offset, blkdev_get_block, - NULL, NULL, 0); + return __blockdev_direct_IO(iocb, inode, I_BDEV(inode), iter, offset, + blkdev_get_block, NULL, NULL, 0); } int __sync_blockdev(struct block_device *bdev, int wait) @@ -1597,9 +1595,22 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; + struct inode *bd_inode = file->f_mapping->host; + loff_t size = i_size_read(bd_inode); struct blk_plug plug; ssize_t ret; + if (bdev_read_only(I_BDEV(bd_inode))) + return -EPERM; + + if (!iov_iter_count(from)) + return 0; + + if (iocb->ki_pos >= size) + return -ENOSPC; + + iov_iter_truncate(from, size - iocb->ki_pos); + blk_start_plug(&plug); ret = __generic_file_write_iter(iocb, from); if (ret > 0) { diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index cdc801c85105..faa7d390841b 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1739,27 +1739,19 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, u64 start_pos; u64 end_pos; ssize_t num_written = 0; - ssize_t err = 0; - size_t count = iov_iter_count(from); bool sync = (file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host); - loff_t pos = iocb->ki_pos; + ssize_t err; + loff_t pos; + size_t count; mutex_lock(&inode->i_mutex); - - current->backing_dev_info = inode_to_bdi(inode); - err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); - if (err) { + err = generic_write_checks(iocb, from); + if (err <= 0) { mutex_unlock(&inode->i_mutex); - goto out; - } - - if (count == 0) { - mutex_unlock(&inode->i_mutex); - goto out; + return err; } - iov_iter_truncate(from, count); - + current->backing_dev_info = inode_to_bdi(inode); err = file_remove_suid(file); if (err) { mutex_unlock(&inode->i_mutex); @@ -1786,6 +1778,8 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, */ update_time_for_write(inode); + pos = iocb->ki_pos; + count = iov_iter_count(from); start_pos = round_down(pos, root->sectorsize); if (start_pos > i_size_read(inode)) { /* Expand hole size to cover write data, preventing empty gap */ @@ -1800,7 +1794,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, if (sync) atomic_inc(&BTRFS_I(inode)->sync_writers); - if (file->f_flags & O_DIRECT) { + if (iocb->ki_flags & IOCB_DIRECT) { num_written = __btrfs_direct_write(iocb, from, pos); } else { num_written = __btrfs_buffered_write(file, from, pos); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 686331f22b15..43192e10cc43 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8081,7 +8081,7 @@ free_ordered: bio_endio(dio_bio, ret); } -static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *iocb, +static ssize_t check_direct_IO(struct btrfs_root *root, struct kiocb *iocb, const struct iov_iter *iter, loff_t offset) { int seg; @@ -8096,7 +8096,7 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io goto out; /* If this is a write we don't need to check anymore */ - if (rw & WRITE) + if (iov_iter_rw(iter) == WRITE) return 0; /* * Check to make sure we don't have duplicate iov_base's in this @@ -8114,8 +8114,8 @@ out: return retval; } -static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -8126,7 +8126,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, bool relock = false; ssize_t ret; - if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iter, offset)) + if (check_direct_IO(BTRFS_I(inode)->root, iocb, iter, offset)) return 0; atomic_inc(&inode->i_dio_count); @@ -8144,7 +8144,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, filemap_fdatawrite_range(inode->i_mapping, offset, offset + count - 1); - if (rw & WRITE) { + if (iov_iter_rw(iter) == WRITE) { /* * If the write DIO is beyond the EOF, we need update * the isize, but it is protected by i_mutex. So we can @@ -8174,11 +8174,11 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, wakeup = false; } - ret = __blockdev_direct_IO(rw, iocb, inode, - BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev, - iter, offset, btrfs_get_blocks_direct, NULL, - btrfs_submit_direct, flags); - if (rw & WRITE) { + ret = __blockdev_direct_IO(iocb, inode, + BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev, + iter, offset, btrfs_get_blocks_direct, NULL, + btrfs_submit_direct, flags); + if (iov_iter_rw(iter) == WRITE) { current->journal_info = NULL; if (ret < 0 && ret != -EIOCBQUEUED) btrfs_delalloc_release_space(inode, count); diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index fd5599d32362..155ab9c0246b 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1198,8 +1198,7 @@ static int ceph_write_end(struct file *file, struct address_space *mapping, * intercept O_DIRECT reads and writes early, this function should * never get called. */ -static ssize_t ceph_direct_io(int rw, struct kiocb *iocb, - struct iov_iter *iter, +static ssize_t ceph_direct_io(struct kiocb *iocb, struct iov_iter *iter, loff_t pos) { WARN_ON(1); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 56237ea5fc22..b9b8eb225f66 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -457,7 +457,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i, if (ret < 0) return ret; - if (file->f_flags & O_DIRECT) { + if (iocb->ki_flags & IOCB_DIRECT) { while (iov_iter_count(i)) { size_t start; ssize_t n; @@ -828,7 +828,7 @@ again: return ret; if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 || - (iocb->ki_filp->f_flags & O_DIRECT) || + (iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC)) { dout("aio_sync_read %p %llx.%llx %llu~%u got cap refs on %s\n", @@ -941,9 +941,9 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->client->osdc; - ssize_t count = iov_iter_count(from), written = 0; + ssize_t count, written = 0; int err, want, got; - loff_t pos = iocb->ki_pos; + loff_t pos; if (ceph_snap(inode) != CEPH_NOSNAP) return -EROFS; @@ -953,14 +953,12 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) /* We can write back this queue in page reclaim */ current->backing_dev_info = inode_to_bdi(inode); - err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); - if (err) - goto out; - - if (count == 0) + err = generic_write_checks(iocb, from); + if (err <= 0) goto out; - iov_iter_truncate(from, count); + pos = iocb->ki_pos; + count = iov_iter_count(from); err = file_remove_suid(file); if (err) goto out; @@ -997,12 +995,12 @@ retry_snap: inode, ceph_vinop(inode), pos, count, ceph_cap_string(got)); if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || - (file->f_flags & O_DIRECT) || (fi->flags & CEPH_F_SYNC)) { + (iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC)) { struct iov_iter data; mutex_unlock(&inode->i_mutex); /* we might need to revert back to that point */ data = *from; - if (file->f_flags & O_DIRECT) + if (iocb->ki_flags & IOCB_DIRECT) written = ceph_sync_direct_write(iocb, &data, pos); else written = ceph_sync_write(iocb, &data, pos); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index ca30c391a894..ca2bc5406306 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -2560,10 +2560,9 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, return rc; } -static ssize_t -cifs_iovec_write(struct file *file, struct iov_iter *from, loff_t *poffset) +ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from) { - size_t len; + struct file *file = iocb->ki_filp; ssize_t total_written = 0; struct cifsFileInfo *open_file; struct cifs_tcon *tcon; @@ -2573,15 +2572,15 @@ cifs_iovec_write(struct file *file, struct iov_iter *from, loff_t *poffset) struct iov_iter saved_from; int rc; - len = iov_iter_count(from); - rc = generic_write_checks(file, poffset, &len, 0); - if (rc) - return rc; - - if (!len) - return 0; + /* + * BB - optimize the way when signing is disabled. We can drop this + * extra memory-to-memory copying and use iovec buffers for constructing + * write request. + */ - iov_iter_truncate(from, len); + rc = generic_write_checks(iocb, from); + if (rc <= 0) + return rc; INIT_LIST_HEAD(&wdata_list); cifs_sb = CIFS_FILE_SB(file); @@ -2593,8 +2592,8 @@ cifs_iovec_write(struct file *file, struct iov_iter *from, loff_t *poffset) memcpy(&saved_from, from, sizeof(struct iov_iter)); - rc = cifs_write_from_iter(*poffset, len, from, open_file, cifs_sb, - &wdata_list); + rc = cifs_write_from_iter(iocb->ki_pos, iov_iter_count(from), from, + open_file, cifs_sb, &wdata_list); /* * If at least one write was successfully sent, then discard any rc @@ -2633,7 +2632,7 @@ restart_loop: memcpy(&tmp_from, &saved_from, sizeof(struct iov_iter)); iov_iter_advance(&tmp_from, - wdata->offset - *poffset); + wdata->offset - iocb->ki_pos); rc = cifs_write_from_iter(wdata->offset, wdata->bytes, &tmp_from, @@ -2650,34 +2649,13 @@ restart_loop: kref_put(&wdata->refcount, cifs_uncached_writedata_release); } - if (total_written > 0) - *poffset += total_written; + if (unlikely(!total_written)) + return rc; + iocb->ki_pos += total_written; + set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(file_inode(file))->flags); cifs_stats_bytes_written(tcon, total_written); - return total_written ? total_written : (ssize_t)rc; -} - -ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from) -{ - ssize_t written; - struct inode *inode; - loff_t pos = iocb->ki_pos; - - inode = file_inode(iocb->ki_filp); - - /* - * BB - optimize the way when signing is disabled. We can drop this - * extra memory-to-memory copying and use iovec buffers for constructing - * write request. - */ - - written = cifs_iovec_write(iocb->ki_filp, from, &pos); - if (written > 0) { - set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(inode)->flags); - iocb->ki_pos = pos; - } - - return written; + return total_written; } static ssize_t @@ -2688,8 +2666,7 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from) struct inode *inode = file->f_mapping->host; struct cifsInodeInfo *cinode = CIFS_I(inode); struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; - ssize_t rc = -EACCES; - loff_t lock_pos = iocb->ki_pos; + ssize_t rc; /* * We need to hold the sem to be sure nobody modifies lock list @@ -2697,23 +2674,24 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from) */ down_read(&cinode->lock_sem); mutex_lock(&inode->i_mutex); - if (file->f_flags & O_APPEND) - lock_pos = i_size_read(inode); - if (!cifs_find_lock_conflict(cfile, lock_pos, iov_iter_count(from), + + rc = generic_write_checks(iocb, from); + if (rc <= 0) + goto out; + + if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(from), server->vals->exclusive_lock_type, NULL, - CIFS_WRITE_OP)) { + CIFS_WRITE_OP)) rc = __generic_file_write_iter(iocb, from); - mutex_unlock(&inode->i_mutex); - - if (rc > 0) { - ssize_t err; + else + rc = -EACCES; +out: + mutex_unlock(&inode->i_mutex); - err = generic_write_sync(file, iocb->ki_pos - rc, rc); - if (err < 0) - rc = err; - } - } else { - mutex_unlock(&inode->i_mutex); + if (rc > 0) { + ssize_t err = generic_write_sync(file, iocb->ki_pos - rc, rc); + if (err < 0) + rc = err; } up_read(&cinode->lock_sem); return rc; @@ -3877,8 +3855,7 @@ void cifs_oplock_break(struct work_struct *work) * Direct IO is not yet supported in the cached mode. */ static ssize_t -cifs_direct_io(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t pos) +cifs_direct_io(struct kiocb *iocb, struct iov_iter *iter, loff_t pos) { /* * FIXME diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index cf0db005d2f5..acb3d63bc9dc 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -1598,7 +1598,7 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence) if (offset >= 0) break; default: - mutex_unlock(&file_inode(file)->i_mutex); + mutex_unlock(&dentry->d_inode->i_mutex); return -EINVAL; } if (offset != file->f_pos) { @@ -98,9 +98,9 @@ static bool buffer_size_valid(struct buffer_head *bh) return bh->b_state != 0; } -static ssize_t dax_io(int rw, struct inode *inode, struct iov_iter *iter, - loff_t start, loff_t end, get_block_t get_block, - struct buffer_head *bh) +static ssize_t dax_io(struct inode *inode, struct iov_iter *iter, + loff_t start, loff_t end, get_block_t get_block, + struct buffer_head *bh) { ssize_t retval = 0; loff_t pos = start; @@ -109,7 +109,7 @@ static ssize_t dax_io(int rw, struct inode *inode, struct iov_iter *iter, void *addr; bool hole = false; - if (rw != WRITE) + if (iov_iter_rw(iter) != WRITE) end = min(end, i_size_read(inode)); while (pos < end) { @@ -124,7 +124,7 @@ static ssize_t dax_io(int rw, struct inode *inode, struct iov_iter *iter, bh->b_size = PAGE_ALIGN(end - pos); bh->b_state = 0; retval = get_block(inode, block, bh, - rw == WRITE); + iov_iter_rw(iter) == WRITE); if (retval) break; if (!buffer_size_valid(bh)) @@ -137,7 +137,7 @@ static ssize_t dax_io(int rw, struct inode *inode, struct iov_iter *iter, bh->b_size -= done; } - hole = (rw != WRITE) && !buffer_written(bh); + hole = iov_iter_rw(iter) != WRITE && !buffer_written(bh); if (hole) { addr = NULL; size = bh->b_size - first; @@ -154,7 +154,7 @@ static ssize_t dax_io(int rw, struct inode *inode, struct iov_iter *iter, max = min(pos + size, end); } - if (rw == WRITE) + if (iov_iter_rw(iter) == WRITE) len = copy_from_iter(addr, max - pos, iter); else if (!hole) len = copy_to_iter(addr, max - pos, iter); @@ -173,7 +173,6 @@ static ssize_t dax_io(int rw, struct inode *inode, struct iov_iter *iter, /** * dax_do_io - Perform I/O to a DAX file - * @rw: READ to read or WRITE to write * @iocb: The control block for this I/O * @inode: The file which the I/O is directed at * @iter: The addresses to do I/O from or to @@ -189,9 +188,9 @@ static ssize_t dax_io(int rw, struct inode *inode, struct iov_iter *iter, * As with do_blockdev_direct_IO(), we increment i_dio_count while the I/O * is in progress. */ -ssize_t dax_do_io(int rw, struct kiocb *iocb, struct inode *inode, - struct iov_iter *iter, loff_t pos, - get_block_t get_block, dio_iodone_t end_io, int flags) +ssize_t dax_do_io(struct kiocb *iocb, struct inode *inode, + struct iov_iter *iter, loff_t pos, get_block_t get_block, + dio_iodone_t end_io, int flags) { struct buffer_head bh; ssize_t retval = -EINVAL; @@ -199,7 +198,7 @@ ssize_t dax_do_io(int rw, struct kiocb *iocb, struct inode *inode, memset(&bh, 0, sizeof(bh)); - if ((flags & DIO_LOCKING) && (rw == READ)) { + if ((flags & DIO_LOCKING) && iov_iter_rw(iter) == READ) { struct address_space *mapping = inode->i_mapping; mutex_lock(&inode->i_mutex); retval = filemap_write_and_wait_range(mapping, pos, end - 1); @@ -212,9 +211,9 @@ ssize_t dax_do_io(int rw, struct kiocb *iocb, struct inode *inode, /* Protects against truncate */ atomic_inc(&inode->i_dio_count); - retval = dax_io(rw, inode, iter, pos, end, get_block, &bh); + retval = dax_io(inode, iter, pos, end, get_block, &bh); - if ((flags & DIO_LOCKING) && (rw == READ)) + if ((flags & DIO_LOCKING) && iov_iter_rw(iter) == READ) mutex_unlock(&inode->i_mutex); if ((retval > 0) && end_io) diff --git a/fs/dcache.c b/fs/dcache.c index d99736a63e3c..656ce522a218 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -269,6 +269,41 @@ static inline int dname_external(const struct dentry *dentry) return dentry->d_name.name != dentry->d_iname; } +/* + * Make sure other CPUs see the inode attached before the type is set. + */ +static inline void __d_set_inode_and_type(struct dentry *dentry, + struct inode *inode, + unsigned type_flags) +{ + unsigned flags; + + dentry->d_inode = inode; + smp_wmb(); + flags = READ_ONCE(dentry->d_flags); + flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); + flags |= type_flags; + WRITE_ONCE(dentry->d_flags, flags); +} + +/* + * Ideally, we want to make sure that other CPUs see the flags cleared before + * the inode is detached, but this is really a violation of RCU principles + * since the ordering suggests we should always set inode before flags. + * + * We should instead replace or discard the entire dentry - but that sucks + * performancewise on mass deletion/rename. + */ +static inline void __d_clear_type_and_inode(struct dentry *dentry) +{ + unsigned flags = READ_ONCE(dentry->d_flags); + + flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); + WRITE_ONCE(dentry->d_flags, flags); + smp_wmb(); + dentry->d_inode = NULL; +} + static void dentry_free(struct dentry *dentry) { WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias)); @@ -311,7 +346,7 @@ static void dentry_iput(struct dentry * dentry) { struct inode *inode = dentry->d_inode; if (inode) { - dentry->d_inode = NULL; + __d_clear_type_and_inode(dentry); hlist_del_init(&dentry->d_u.d_alias); spin_unlock(&dentry->d_lock); spin_unlock(&inode->i_lock); @@ -335,8 +370,7 @@ static void dentry_unlink_inode(struct dentry * dentry) __releases(dentry->d_inode->i_lock) { struct inode *inode = dentry->d_inode; - __d_clear_type(dentry); - dentry->d_inode = NULL; + __d_clear_type_and_inode(dentry); hlist_del_init(&dentry->d_u.d_alias); dentry_rcuwalk_barrier(dentry); spin_unlock(&dentry->d_lock); @@ -1715,11 +1749,9 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) unsigned add_flags = d_flags_for_inode(inode); spin_lock(&dentry->d_lock); - dentry->d_flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); - dentry->d_flags |= add_flags; if (inode) hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); - dentry->d_inode = inode; + __d_set_inode_and_type(dentry, inode, add_flags); dentry_rcuwalk_barrier(dentry); spin_unlock(&dentry->d_lock); fsnotify_d_instantiate(dentry, inode); @@ -1937,8 +1969,7 @@ static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected) add_flags |= DCACHE_DISCONNECTED; spin_lock(&tmp->d_lock); - tmp->d_inode = inode; - tmp->d_flags |= add_flags; + __d_set_inode_and_type(tmp, inode, add_flags); hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry); hlist_bl_lock(&tmp->d_sb->s_anon); hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 61e72d44cf94..c9ee0dfe90b5 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -524,7 +524,7 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent) if (debugfs_positive(dentry)) { dget(dentry); - if (S_ISDIR(dentry->d_inode->i_mode)) + if (d_is_dir(dentry)) ret = simple_rmdir(parent->d_inode, dentry); else simple_unlink(parent->d_inode, dentry); diff --git a/fs/direct-io.c b/fs/direct-io.c index 6fb00e3f1059..c3b560b24a46 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1093,10 +1093,10 @@ static inline int drop_refcount(struct dio *dio) * for the whole file. */ static inline ssize_t -do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, - struct block_device *bdev, struct iov_iter *iter, loff_t offset, - get_block_t get_block, dio_iodone_t end_io, - dio_submit_t submit_io, int flags) +do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, + struct block_device *bdev, struct iov_iter *iter, + loff_t offset, get_block_t get_block, dio_iodone_t end_io, + dio_submit_t submit_io, int flags) { unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits); unsigned blkbits = i_blkbits; @@ -1110,9 +1110,6 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, struct blk_plug plug; unsigned long align = offset | iov_iter_alignment(iter); - if (rw & WRITE) - rw = WRITE_ODIRECT; - /* * Avoid references to bdev if not absolutely needed to give * the early prefetch in the caller enough time. @@ -1127,7 +1124,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, } /* watch out for a 0 len io from a tricksy fs */ - if (rw == READ && !iov_iter_count(iter)) + if (iov_iter_rw(iter) == READ && !iov_iter_count(iter)) return 0; dio = kmem_cache_alloc(dio_cache, GFP_KERNEL); @@ -1143,7 +1140,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, dio->flags = flags; if (dio->flags & DIO_LOCKING) { - if (rw == READ) { + if (iov_iter_rw(iter) == READ) { struct address_space *mapping = iocb->ki_filp->f_mapping; @@ -1169,19 +1166,19 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, if (is_sync_kiocb(iocb)) dio->is_async = false; else if (!(dio->flags & DIO_ASYNC_EXTEND) && - (rw & WRITE) && end > i_size_read(inode)) + iov_iter_rw(iter) == WRITE && end > i_size_read(inode)) dio->is_async = false; else dio->is_async = true; dio->inode = inode; - dio->rw = rw; + dio->rw = iov_iter_rw(iter) == WRITE ? WRITE_ODIRECT : READ; /* * For AIO O_(D)SYNC writes we need to defer completions to a workqueue * so that we can call ->fsync. */ - if (dio->is_async && (rw & WRITE) && + if (dio->is_async && iov_iter_rw(iter) == WRITE && ((iocb->ki_filp->f_flags & O_DSYNC) || IS_SYNC(iocb->ki_filp->f_mapping->host))) { retval = dio_set_defer_completion(dio); @@ -1274,7 +1271,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, * we can let i_mutex go now that its achieved its purpose * of protecting us from looking up uninitialized blocks. */ - if (rw == READ && (dio->flags & DIO_LOCKING)) + if (iov_iter_rw(iter) == READ && (dio->flags & DIO_LOCKING)) mutex_unlock(&dio->inode->i_mutex); /* @@ -1286,7 +1283,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, */ BUG_ON(retval == -EIOCBQUEUED); if (dio->is_async && retval == 0 && dio->result && - (rw == READ || dio->result == count)) + (iov_iter_rw(iter) == READ || dio->result == count)) retval = -EIOCBQUEUED; else dio_await_completion(dio); @@ -1300,11 +1297,11 @@ out: return retval; } -ssize_t -__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, - struct block_device *bdev, struct iov_iter *iter, loff_t offset, - get_block_t get_block, dio_iodone_t end_io, - dio_submit_t submit_io, int flags) +ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, + struct block_device *bdev, struct iov_iter *iter, + loff_t offset, get_block_t get_block, + dio_iodone_t end_io, dio_submit_t submit_io, + int flags) { /* * The block device state is needed in the end to finally @@ -1318,8 +1315,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, prefetch(bdev->bd_queue); prefetch((char *)bdev->bd_queue + SMP_CACHE_BYTES); - return do_blockdev_direct_IO(rw, iocb, inode, bdev, iter, offset, - get_block, end_io, submit_io, flags); + return do_blockdev_direct_IO(iocb, inode, bdev, iter, offset, get_block, + end_io, submit_io, flags); } EXPORT_SYMBOL(__blockdev_direct_IO); diff --git a/fs/exec.c b/fs/exec.c index c7f9b733406d..02bfd980a40c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -926,10 +926,14 @@ static int de_thread(struct task_struct *tsk) if (!thread_group_leader(tsk)) { struct task_struct *leader = tsk->group_leader; - sig->notify_count = -1; /* for exit_notify() */ for (;;) { threadgroup_change_begin(tsk); write_lock_irq(&tasklist_lock); + /* + * Do this under tasklist_lock to ensure that + * exit_notify() can't miss ->group_exit_task + */ + sig->notify_count = -1; if (likely(leader->exit_state)) break; __set_current_state(TASK_KILLABLE); @@ -1078,7 +1082,13 @@ int flush_old_exec(struct linux_binprm * bprm) if (retval) goto out; + /* + * Must be called _before_ exec_mmap() as bprm->mm is + * not visibile until then. This also enables the update + * to be lockless. + */ set_mm_exe_file(bprm->mm, bprm->file); + /* * Release all of the old mmap stuff */ diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index a198e94813fe..35073aaec6e0 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -963,8 +963,8 @@ static void exofs_invalidatepage(struct page *page, unsigned int offset, /* TODO: Should be easy enough to do proprly */ -static ssize_t exofs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t exofs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { return 0; } diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index b29eb6747116..5d9213963fae 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -851,8 +851,7 @@ static sector_t ext2_bmap(struct address_space *mapping, sector_t block) } static ssize_t -ext2_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) +ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -861,12 +860,12 @@ ext2_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, ssize_t ret; if (IS_DAX(inode)) - ret = dax_do_io(rw, iocb, inode, iter, offset, ext2_get_block, - NULL, DIO_LOCKING); + ret = dax_do_io(iocb, inode, iter, offset, ext2_get_block, NULL, + DIO_LOCKING); else - ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, + ret = blockdev_direct_IO(iocb, inode, iter, offset, ext2_get_block); - if (ret < 0 && (rw & WRITE)) + if (ret < 0 && iov_iter_rw(iter) == WRITE) ext2_write_failed(mapping, offset + count); return ret; } diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index db07ffbe7c85..13c0868c7160 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1820,8 +1820,8 @@ static int ext3_releasepage(struct page *page, gfp_t wait) * crashes then stale disk data _may_ be exposed inside the file. But current * VFS code falls back into buffered path in that case so we are safe. */ -static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t ext3_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -1832,9 +1832,9 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, size_t count = iov_iter_count(iter); int retries = 0; - trace_ext3_direct_IO_enter(inode, offset, count, rw); + trace_ext3_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); - if (rw == WRITE) { + if (iov_iter_rw(iter) == WRITE) { loff_t final_size = offset + count; if (final_size > inode->i_size) { @@ -1856,12 +1856,12 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, } retry: - ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, ext3_get_block); + ret = blockdev_direct_IO(iocb, inode, iter, offset, ext3_get_block); /* * In case of error extending write may have instantiated a few * blocks outside i_size. Trim these off again. */ - if (unlikely((rw & WRITE) && ret < 0)) { + if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { loff_t isize = i_size_read(inode); loff_t end = offset + count; @@ -1908,7 +1908,7 @@ retry: ret = err; } out: - trace_ext3_direct_IO_exit(inode, offset, count, rw, ret); + trace_ext3_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret); return ret; } diff --git a/fs/ext3/super.c b/fs/ext3/super.c index d4dbf3c259b3..f037b4b27300 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -789,7 +789,7 @@ static const struct quotactl_ops ext3_qctl_operations = { .quota_on = ext3_quota_on, .quota_off = dquot_quota_off, .quota_sync = dquot_quota_sync, - .get_info = dquot_get_dqinfo, + .get_state = dquot_get_state, .set_info = dquot_set_dqinfo, .get_dqblk = dquot_get_dqblk, .set_dqblk = dquot_set_dqblk diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index c6874be6d58b..24215dc09a18 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -546,8 +546,7 @@ ext3_xattr_set_entry(struct ext3_xattr_info *i, struct ext3_xattr_search *s) free += EXT3_XATTR_LEN(name_len); } if (i->value) { - if (free < EXT3_XATTR_SIZE(i->value_len) || - free < EXT3_XATTR_LEN(name_len) + + if (free < EXT3_XATTR_LEN(name_len) + EXT3_XATTR_SIZE(i->value_len)) return -ENOSPC; } diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 8a3981ea35d8..c8eb32eefc3c 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2152,8 +2152,8 @@ extern void ext4_da_update_reserve_space(struct inode *inode, /* indirect.c */ extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, int flags); -extern ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset); +extern ssize_t ext4_ind_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset); extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock); extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks); extern void ext4_ind_truncate(handle_t *, struct inode *inode); diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 7a6defcf3352..e576d682b353 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -95,11 +95,9 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) struct inode *inode = file_inode(iocb->ki_filp); struct mutex *aio_mutex = NULL; struct blk_plug plug; - int o_direct = io_is_direct(file); + int o_direct = iocb->ki_flags & IOCB_DIRECT; int overwrite = 0; - size_t length = iov_iter_count(from); ssize_t ret; - loff_t pos = iocb->ki_pos; /* * Unaligned direct AIO must be serialized; see comment above @@ -108,16 +106,17 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (o_direct && ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && !is_sync_kiocb(iocb) && - (file->f_flags & O_APPEND || - ext4_unaligned_aio(inode, from, pos))) { + (iocb->ki_flags & IOCB_APPEND || + ext4_unaligned_aio(inode, from, iocb->ki_pos))) { aio_mutex = ext4_aio_mutex(inode); mutex_lock(aio_mutex); ext4_unwritten_wait(inode); } mutex_lock(&inode->i_mutex); - if (file->f_flags & O_APPEND) - iocb->ki_pos = pos = i_size_read(inode); + ret = generic_write_checks(iocb, from); + if (ret <= 0) + goto out; /* * If we have encountered a bitmap-format file, the size limit @@ -126,22 +125,19 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - if ((pos > sbi->s_bitmap_maxbytes) || - (pos == sbi->s_bitmap_maxbytes && length > 0)) { - mutex_unlock(&inode->i_mutex); + if (iocb->ki_pos >= sbi->s_bitmap_maxbytes) { ret = -EFBIG; - goto errout; + goto out; } - - if (pos + length > sbi->s_bitmap_maxbytes) - iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos); + iov_iter_truncate(from, sbi->s_bitmap_maxbytes - iocb->ki_pos); } iocb->private = &overwrite; if (o_direct) { + size_t length = iov_iter_count(from); + loff_t pos = iocb->ki_pos; blk_start_plug(&plug); - /* check whether we do a DIO overwrite or not */ if (ext4_should_dioread_nolock(inode) && !aio_mutex && !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { @@ -185,7 +181,12 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (o_direct) blk_finish_plug(&plug); -errout: + if (aio_mutex) + mutex_unlock(aio_mutex); + return ret; + +out: + mutex_unlock(&inode->i_mutex); if (aio_mutex) mutex_unlock(aio_mutex); return ret; diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index 740c7871c117..3580629e42d3 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -642,8 +642,8 @@ out: * crashes then stale disk data _may_ be exposed inside the file. But current * VFS code falls back into buffered path in that case so we are safe. */ -ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +ssize_t ext4_ind_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -654,7 +654,7 @@ ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, size_t count = iov_iter_count(iter); int retries = 0; - if (rw == WRITE) { + if (iov_iter_rw(iter) == WRITE) { loff_t final_size = offset + count; if (final_size > inode->i_size) { @@ -676,7 +676,7 @@ ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, } retry: - if (rw == READ && ext4_should_dioread_nolock(inode)) { + if (iov_iter_rw(iter) == READ && ext4_should_dioread_nolock(inode)) { /* * Nolock dioread optimization may be dynamically disabled * via ext4_inode_block_unlocked_dio(). Check inode's state @@ -690,23 +690,24 @@ retry: goto locked; } if (IS_DAX(inode)) - ret = dax_do_io(rw, iocb, inode, iter, offset, + ret = dax_do_io(iocb, inode, iter, offset, ext4_get_block, NULL, 0); else - ret = __blockdev_direct_IO(rw, iocb, inode, - inode->i_sb->s_bdev, iter, offset, - ext4_get_block, NULL, NULL, 0); + ret = __blockdev_direct_IO(iocb, inode, + inode->i_sb->s_bdev, iter, + offset, ext4_get_block, NULL, + NULL, 0); inode_dio_done(inode); } else { locked: if (IS_DAX(inode)) - ret = dax_do_io(rw, iocb, inode, iter, offset, + ret = dax_do_io(iocb, inode, iter, offset, ext4_get_block, NULL, DIO_LOCKING); else - ret = blockdev_direct_IO(rw, iocb, inode, iter, - offset, ext4_get_block); + ret = blockdev_direct_IO(iocb, inode, iter, offset, + ext4_get_block); - if (unlikely((rw & WRITE) && ret < 0)) { + if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { loff_t isize = i_size_read(inode); loff_t end = offset + count; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 035b7a06f1c3..b49cf6e59953 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2952,8 +2952,8 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, * if the machine crashes during the write. * */ -static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -2966,8 +2966,8 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, ext4_io_end_t *io_end = NULL; /* Use the old path for reads and writes beyond i_size. */ - if (rw != WRITE || final_size > inode->i_size) - return ext4_ind_direct_IO(rw, iocb, iter, offset); + if (iov_iter_rw(iter) != WRITE || final_size > inode->i_size) + return ext4_ind_direct_IO(iocb, iter, offset); BUG_ON(iocb->private == NULL); @@ -2976,7 +2976,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, * conversion. This also disallows race between truncate() and * overwrite DIO as i_dio_count needs to be incremented under i_mutex. */ - if (rw == WRITE) + if (iov_iter_rw(iter) == WRITE) atomic_inc(&inode->i_dio_count); /* If we do a overwrite dio, i_mutex locking can be released */ @@ -3034,10 +3034,10 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, dio_flags = DIO_LOCKING; } if (IS_DAX(inode)) - ret = dax_do_io(rw, iocb, inode, iter, offset, get_block_func, + ret = dax_do_io(iocb, inode, iter, offset, get_block_func, ext4_end_io_dio, dio_flags); else - ret = __blockdev_direct_IO(rw, iocb, inode, + ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, offset, get_block_func, ext4_end_io_dio, NULL, dio_flags); @@ -3078,7 +3078,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, } retake_lock: - if (rw == WRITE) + if (iov_iter_rw(iter) == WRITE) inode_dio_done(inode); /* take i_mutex locking again if we do a ovewrite dio */ if (overwrite) { @@ -3089,8 +3089,8 @@ retake_lock: return ret; } -static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -3107,12 +3107,12 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, if (ext4_has_inline_data(inode)) return 0; - trace_ext4_direct_IO_enter(inode, offset, count, rw); + trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - ret = ext4_ext_direct_IO(rw, iocb, iter, offset); + ret = ext4_ext_direct_IO(iocb, iter, offset); else - ret = ext4_ind_direct_IO(rw, iocb, iter, offset); - trace_ext4_direct_IO_exit(inode, offset, count, rw, ret); + ret = ext4_ind_direct_IO(iocb, iter, offset); + trace_ext4_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret); return ret; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e061e66c8280..d348c7d29d80 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1076,7 +1076,7 @@ static const struct quotactl_ops ext4_qctl_operations = { .quota_on = ext4_quota_on, .quota_off = ext4_quota_off, .quota_sync = dquot_quota_sync, - .get_info = dquot_get_dqinfo, + .get_state = dquot_get_state, .set_info = dquot_set_dqinfo, .get_dqblk = dquot_get_dqblk, .set_dqblk = dquot_set_dqblk diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 497f8515d205..319eda511c4f 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1118,12 +1118,12 @@ static int f2fs_write_end(struct file *file, return copied; } -static int check_direct_IO(struct inode *inode, int rw, - struct iov_iter *iter, loff_t offset) +static int check_direct_IO(struct inode *inode, struct iov_iter *iter, + loff_t offset) { unsigned blocksize_mask = inode->i_sb->s_blocksize - 1; - if (rw == READ) + if (iov_iter_rw(iter) == READ) return 0; if (offset & blocksize_mask) @@ -1135,8 +1135,8 @@ static int check_direct_IO(struct inode *inode, int rw, return 0; } -static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -1151,19 +1151,19 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, return err; } - if (check_direct_IO(inode, rw, iter, offset)) + if (check_direct_IO(inode, iter, offset)) return 0; - trace_f2fs_direct_IO_enter(inode, offset, count, rw); + trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); - if (rw & WRITE) + if (iov_iter_rw(iter) == WRITE) __allocate_data_blocks(inode, offset, count); - err = blockdev_direct_IO(rw, iocb, inode, iter, offset, get_data_block); - if (err < 0 && (rw & WRITE)) + err = blockdev_direct_IO(iocb, inode, iter, offset, get_data_block); + if (err < 0 && iov_iter_rw(iter) == WRITE) f2fs_write_failed(mapping, offset + count); - trace_f2fs_direct_IO_exit(inode, offset, count, rw, err); + trace_f2fs_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), err); return err; } diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 91ad9e1c9441..93fc62232ec2 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -8,9 +8,7 @@ * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers. */ -#include <linux/fs.h> #include <linux/slab.h> -#include <linux/buffer_head.h> #include "fat.h" /* this must be > 0. */ diff --git a/fs/fat/dir.c b/fs/fat/dir.c index c5d6bb939d19..4afc4d9d2e41 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -13,13 +13,9 @@ * Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de> */ -#include <linux/module.h> #include <linux/slab.h> -#include <linux/time.h> -#include <linux/buffer_head.h> #include <linux/compat.h> #include <linux/uaccess.h> -#include <linux/kernel.h> #include "fat.h" /* diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 64e295e8ff38..be5e15323bab 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -2,11 +2,8 @@ #define _FAT_H #include <linux/buffer_head.h> -#include <linux/string.h> #include <linux/nls.h> -#include <linux/fs.h> #include <linux/hash.h> -#include <linux/mutex.h> #include <linux/ratelimit.h> #include <linux/msdos_fs.h> @@ -66,7 +63,7 @@ struct msdos_sb_info { unsigned short sec_per_clus; /* sectors/cluster */ unsigned short cluster_bits; /* log2(cluster_size) */ unsigned int cluster_size; /* cluster size */ - unsigned char fats, fat_bits; /* number of FATs, FAT bits (12 or 16) */ + unsigned char fats, fat_bits; /* number of FATs, FAT bits (12,16 or 32) */ unsigned short fat_start; unsigned long fat_length; /* FAT start & length (sec.) */ unsigned long dir_start; diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 260705c58062..8226557130a2 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -3,9 +3,6 @@ * Released under GPL v2. */ -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/msdos_fs.h> #include <linux/blkdev.h> #include "fat.h" diff --git a/fs/fat/file.c b/fs/fat/file.c index 1e98d333879f..cf50d93565a2 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -10,10 +10,6 @@ #include <linux/module.h> #include <linux/compat.h> #include <linux/mount.h> -#include <linux/time.h> -#include <linux/buffer_head.h> -#include <linux/writeback.h> -#include <linux/backing-dev.h> #include <linux/blkdev.h> #include <linux/fsnotify.h> #include <linux/security.h> diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 8521207de229..c06774658345 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -11,20 +11,12 @@ */ #include <linux/module.h> -#include <linux/init.h> -#include <linux/time.h> -#include <linux/slab.h> -#include <linux/seq_file.h> #include <linux/pagemap.h> #include <linux/mpage.h> -#include <linux/buffer_head.h> -#include <linux/mount.h> #include <linux/vfs.h> +#include <linux/seq_file.h> #include <linux/parser.h> #include <linux/uio.h> -#include <linux/writeback.h> -#include <linux/log2.h> -#include <linux/hash.h> #include <linux/blkdev.h> #include <asm/unaligned.h> #include "fat.h" @@ -245,8 +237,7 @@ static int fat_write_end(struct file *file, struct address_space *mapping, return err; } -static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, +static ssize_t fat_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; @@ -255,7 +246,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, size_t count = iov_iter_count(iter); ssize_t ret; - if (rw == WRITE) { + if (iov_iter_rw(iter) == WRITE) { /* * FIXME: blockdev_direct_IO() doesn't use ->write_begin(), * so we need to update the ->mmu_private to block boundary. @@ -274,8 +265,8 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, * FAT need to use the DIO_LOCKING for avoiding the race * condition of fat_get_block() and ->truncate(). */ - ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, fat_get_block); - if (ret < 0 && (rw & WRITE)) + ret = blockdev_direct_IO(iocb, inode, iter, offset, fat_get_block); + if (ret < 0 && iov_iter_rw(iter) == WRITE) fat_write_failed(mapping, offset + count); return ret; @@ -1279,8 +1270,7 @@ out: static int fat_read_root(struct inode *inode) { - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); + struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); int error; MSDOS_I(inode)->i_pos = MSDOS_ROOT_INO; diff --git a/fs/fat/misc.c b/fs/fat/misc.c index d8da2d2e30ae..c4589e981760 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -6,10 +6,6 @@ * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) */ -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/buffer_head.h> -#include <linux/time.h> #include "fat.h" /* diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index a783b0e1272a..cc6a8541b668 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -7,8 +7,6 @@ */ #include <linux/module.h> -#include <linux/time.h> -#include <linux/buffer_head.h> #include "fat.h" /* Characters that are undesirable in an MS-DOS file name */ diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index b8b92c2f9683..7e0974eebd8e 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -16,10 +16,8 @@ */ #include <linux/module.h> -#include <linux/jiffies.h> #include <linux/ctype.h> #include <linux/slab.h> -#include <linux/buffer_head.h> #include <linux/namei.h> #include "fat.h" diff --git a/fs/file.c b/fs/file.c index ee738ea028fa..93c5f89c248b 100644 --- a/fs/file.c +++ b/fs/file.c @@ -638,8 +638,7 @@ static struct file *__fget(unsigned int fd, fmode_t mask) file = fcheck_files(files, fd); if (file) { /* File object ref couldn't be taken */ - if ((file->f_mode & mask) || - !atomic_long_inc_not_zero(&file->f_count)) + if ((file->f_mode & mask) || !get_file_rcu(file)) file = NULL; } rcu_read_unlock(); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index e1afdd7abf90..5ef05b5c4cff 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1145,13 +1145,11 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; - size_t count = iov_iter_count(from); ssize_t written = 0; ssize_t written_buffered = 0; struct inode *inode = mapping->host; ssize_t err; loff_t endbyte = 0; - loff_t pos = iocb->ki_pos; if (get_fuse_conn(inode)->writeback_cache) { /* Update size (EOF optimization) and mode (SUID clearing) */ @@ -1167,14 +1165,10 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) /* We can write back this queue in page reclaim */ current->backing_dev_info = inode_to_bdi(inode); - err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); - if (err) - goto out; - - if (count == 0) + err = generic_write_checks(iocb, from); + if (err <= 0) goto out; - iov_iter_truncate(from, count); err = file_remove_suid(file); if (err) goto out; @@ -1183,7 +1177,8 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (err) goto out; - if (file->f_flags & O_DIRECT) { + if (iocb->ki_flags & IOCB_DIRECT) { + loff_t pos = iocb->ki_pos; written = generic_file_direct_write(iocb, from, pos); if (written < 0 || !iov_iter_count(from)) goto out; @@ -1209,9 +1204,9 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) written += written_buffered; iocb->ki_pos = pos + written_buffered; } else { - written = fuse_perform_write(file, mapping, from, pos); + written = fuse_perform_write(file, mapping, from, iocb->ki_pos); if (written >= 0) - iocb->ki_pos = pos + written; + iocb->ki_pos += written; } out: current->backing_dev_info = NULL; @@ -1412,7 +1407,6 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from) struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); struct fuse_io_priv io = { .async = 0, .file = file }; - size_t count = iov_iter_count(from); ssize_t res; if (is_bad_inode(inode)) @@ -1420,11 +1414,9 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from) /* Don't allow parallel writes to the same file */ mutex_lock(&inode->i_mutex); - res = generic_write_checks(file, &iocb->ki_pos, &count, 0); - if (!res) { - iov_iter_truncate(from, count); + res = generic_write_checks(iocb, from); + if (res > 0) res = fuse_direct_io(&io, from, &iocb->ki_pos, FUSE_DIO_WRITE); - } fuse_invalidate_attr(inode); if (res > 0) fuse_write_update_size(inode, iocb->ki_pos); @@ -2782,8 +2774,7 @@ static inline loff_t fuse_round_up(loff_t off) } static ssize_t -fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) +fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { DECLARE_COMPLETION_ONSTACK(wait); ssize_t ret = 0; @@ -2800,15 +2791,15 @@ fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, inode = file->f_mapping->host; i_size = i_size_read(inode); - if ((rw == READ) && (offset > i_size)) + if ((iov_iter_rw(iter) == READ) && (offset > i_size)) return 0; /* optimization for short read */ - if (async_dio && rw != WRITE && offset + count > i_size) { + if (async_dio && iov_iter_rw(iter) != WRITE && offset + count > i_size) { if (offset >= i_size) return 0; - count = min_t(loff_t, count, fuse_round_up(i_size - offset)); - iov_iter_truncate(iter, count); + iov_iter_truncate(iter, fuse_round_up(i_size - offset)); + count = iov_iter_count(iter); } io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); @@ -2819,7 +2810,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, io->bytes = -1; io->size = 0; io->offset = offset; - io->write = (rw == WRITE); + io->write = (iov_iter_rw(iter) == WRITE); io->err = 0; io->file = file; /* @@ -2834,19 +2825,15 @@ fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, * to wait on real async I/O requests, so we must submit this request * synchronously. */ - if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE) + if (!is_sync_kiocb(iocb) && (offset + count > i_size) && + iov_iter_rw(iter) == WRITE) io->async = false; if (io->async && is_sync_kiocb(iocb)) io->done = &wait; - if (rw == WRITE) { - ret = generic_write_checks(file, &pos, &count, 0); - if (!ret) { - iov_iter_truncate(iter, count); - ret = fuse_direct_io(io, iter, &pos, FUSE_DIO_WRITE); - } - + if (iov_iter_rw(iter) == WRITE) { + ret = fuse_direct_io(io, iter, &pos, FUSE_DIO_WRITE); fuse_invalidate_attr(inode); } else { ret = __fuse_direct_read(io, iter, &pos); @@ -2865,7 +2852,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, kfree(io); - if (rw == WRITE) { + if (iov_iter_rw(iter) == WRITE) { if (ret > 0) fuse_write_update_size(inode, pos); else if (ret < 0 && offset + count > i_size) diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index a6e6990aea39..5551fea0afd7 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -1016,13 +1016,12 @@ out: /** * gfs2_ok_for_dio - check that dio is valid on this file * @ip: The inode - * @rw: READ or WRITE * @offset: The offset at which we are reading or writing * * Returns: 0 (to ignore the i/o request and thus fall back to buffered i/o) * 1 (to accept the i/o request) */ -static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset) +static int gfs2_ok_for_dio(struct gfs2_inode *ip, loff_t offset) { /* * Should we return an error here? I can't see that O_DIRECT for @@ -1039,8 +1038,8 @@ static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset) -static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t gfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -1061,7 +1060,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, rv = gfs2_glock_nq(&gh); if (rv) return rv; - rv = gfs2_ok_for_dio(ip, rw, offset); + rv = gfs2_ok_for_dio(ip, offset); if (rv != 1) goto out; /* dio not valid, fall back to buffered i/o */ @@ -1091,13 +1090,12 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, rv = filemap_write_and_wait_range(mapping, lstart, end); if (rv) goto out; - if (rw == WRITE) + if (iov_iter_rw(iter) == WRITE) truncate_inode_pages_range(mapping, lstart, end); } - rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, - iter, offset, - gfs2_get_block_direct, NULL, NULL, 0); + rv = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, + offset, gfs2_get_block_direct, NULL, NULL, 0); out: gfs2_glock_dq(&gh); gfs2_holder_uninit(&gh); diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 207eb4a8135e..31892871ea87 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -709,7 +709,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from)); - if (file->f_flags & O_APPEND) { + if (iocb->ki_flags & IOCB_APPEND) { struct gfs2_holder gh; ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 5c27e48aa76f..e3065cb9ab08 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1494,32 +1494,34 @@ int gfs2_quotad(void *data) return 0; } -static int gfs2_quota_get_xstate(struct super_block *sb, - struct fs_quota_stat *fqs) +static int gfs2_quota_get_state(struct super_block *sb, struct qc_state *state) { struct gfs2_sbd *sdp = sb->s_fs_info; - memset(fqs, 0, sizeof(struct fs_quota_stat)); - fqs->qs_version = FS_QSTAT_VERSION; + memset(state, 0, sizeof(*state)); switch (sdp->sd_args.ar_quota) { case GFS2_QUOTA_ON: - fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD); + state->s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED; + state->s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED; /*FALLTHRU*/ case GFS2_QUOTA_ACCOUNT: - fqs->qs_flags |= (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT); + state->s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED | + QCI_SYSFILE; + state->s_state[GRPQUOTA].flags |= QCI_ACCT_ENABLED | + QCI_SYSFILE; break; case GFS2_QUOTA_OFF: break; } - if (sdp->sd_quota_inode) { - fqs->qs_uquota.qfs_ino = GFS2_I(sdp->sd_quota_inode)->i_no_addr; - fqs->qs_uquota.qfs_nblks = sdp->sd_quota_inode->i_blocks; + state->s_state[USRQUOTA].ino = + GFS2_I(sdp->sd_quota_inode)->i_no_addr; + state->s_state[USRQUOTA].blocks = sdp->sd_quota_inode->i_blocks; } - fqs->qs_uquota.qfs_nextents = 1; /* unsupported */ - fqs->qs_gquota = fqs->qs_uquota; /* its the same inode in both cases */ - fqs->qs_incoredqs = list_lru_count(&gfs2_qd_lru); + state->s_state[USRQUOTA].nextents = 1; /* unsupported */ + state->s_state[GRPQUOTA] = state->s_state[USRQUOTA]; + state->s_incoredqs = list_lru_count(&gfs2_qd_lru); return 0; } @@ -1664,7 +1666,7 @@ out_put: const struct quotactl_ops gfs2_quotactl_ops = { .quota_sync = gfs2_quota_sync, - .get_xstate = gfs2_quota_get_xstate, + .get_state = gfs2_quota_get_state, .get_dqblk = gfs2_get_dqblk, .set_dqblk = gfs2_set_dqblk, }; diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 145566851e7a..36d1a6ae7655 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -197,7 +197,7 @@ static int hfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, inode = hfs_new_inode(dir, &dentry->d_name, mode); if (!inode) - return -ENOSPC; + return -ENOMEM; res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); if (res) { @@ -226,7 +226,7 @@ static int hfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode); if (!inode) - return -ENOSPC; + return -ENOMEM; res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); if (res) { diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 9337065bcc67..75fd5d873c19 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -124,8 +124,8 @@ static int hfs_releasepage(struct page *page, gfp_t mask) return res ? try_to_free_buffers(page) : 0; } -static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t hfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -133,13 +133,13 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, hfs_get_block); + ret = blockdev_direct_IO(iocb, inode, iter, offset, hfs_get_block); /* * In case of error extending write may have instantiated a few * blocks outside i_size. Trim these off again. */ - if (unlikely((rw & WRITE) && ret < 0)) { + if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { loff_t isize = i_size_read(inode); loff_t end = offset + count; diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c index c1422d91cd36..528e38b5af7f 100644 --- a/fs/hfsplus/bfind.c +++ b/fs/hfsplus/bfind.c @@ -118,9 +118,7 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd, int b, e; int res; - if (!rec_found) - BUG(); - + BUG_ON(!rec_found); b = 0; e = bnode->num_recs - 1; res = -ENOENT; diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 7892e6fddb66..022974ab6e3c 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c @@ -350,10 +350,11 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) &fd.search_key->cat.name.unicode, off + 2, len); fd.search_key->key_len = cpu_to_be16(6 + len); - } else + } else { err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); if (unlikely(err)) goto out; + } err = hfs_brec_find(&fd, hfs_find_rec_by_key); if (err) diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index f0235c1640af..3074609befc3 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -434,7 +434,7 @@ static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, { struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); struct inode *inode; - int res = -ENOSPC; + int res = -ENOMEM; mutex_lock(&sbi->vh_mutex); inode = hfsplus_new_inode(dir->i_sb, S_IFLNK | S_IRWXUGO); @@ -476,7 +476,7 @@ static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, { struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); struct inode *inode; - int res = -ENOSPC; + int res = -ENOMEM; mutex_lock(&sbi->vh_mutex); inode = hfsplus_new_inode(dir->i_sb, mode); diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 5f86cadb0542..b0afedbef12b 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -122,8 +122,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) return res ? try_to_free_buffers(page) : 0; } -static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -131,14 +131,13 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, - hfsplus_get_block); + ret = blockdev_direct_IO(iocb, inode, iter, offset, hfsplus_get_block); /* * In case of error extending write may have instantiated a few * blocks outside i_size. Trim these off again. */ - if (unlikely((rw & WRITE) && ret < 0)) { + if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { loff_t isize = i_size_read(inode); loff_t end = offset + count; @@ -254,6 +253,12 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size != i_size_read(inode)) { inode_dio_wait(inode); + if (attr->ia_size > inode->i_size) { + error = generic_cont_expand_simple(inode, + attr->ia_size); + if (error) + return error; + } truncate_setsize(inode, attr->ia_size); hfsplus_file_truncate(inode); } diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index d3ff5cc317d7..8e98f5db6ad6 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c @@ -76,7 +76,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags) { struct inode *inode = file_inode(file); struct hfsplus_inode_info *hip = HFSPLUS_I(inode); - unsigned int flags; + unsigned int flags, new_fl = 0; int err = 0; err = mnt_want_write_file(file); @@ -110,14 +110,12 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags) } if (flags & FS_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; + new_fl |= S_IMMUTABLE; if (flags & FS_APPEND_FL) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; + new_fl |= S_APPEND; + + inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND); if (flags & FS_NODUMP_FL) hip->userflags |= HFSPLUS_FLG_NODUMP; diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index d98094a9f476..89f262d8fcd8 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -44,7 +44,7 @@ static int strcmp_xattr_acl(const char *name) return -1; } -static inline int is_known_namespace(const char *name) +static bool is_known_namespace(const char *name) { if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) && strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && @@ -424,6 +424,28 @@ static int copy_name(char *buffer, const char *xattr_name, int name_len) return len; } +int hfsplus_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, + const char *prefix, size_t prefixlen) +{ + char *xattr_name; + int res; + + if (!strcmp(name, "")) + return -EINVAL; + + xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, + GFP_KERNEL); + if (!xattr_name) + return -ENOMEM; + strcpy(xattr_name, prefix); + strcpy(xattr_name + prefixlen, name); + res = __hfsplus_setxattr(dentry->d_inode, xattr_name, value, size, + flags); + kfree(xattr_name); + return res; +} + static ssize_t hfsplus_getxattr_finder_info(struct inode *inode, void *value, size_t size) { @@ -560,6 +582,30 @@ failed_getxattr_init: return res; } +ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, + void *value, size_t size, + const char *prefix, size_t prefixlen) +{ + int res; + char *xattr_name; + + if (!strcmp(name, "")) + return -EINVAL; + + xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, + GFP_KERNEL); + if (!xattr_name) + return -ENOMEM; + + strcpy(xattr_name, prefix); + strcpy(xattr_name + prefixlen, name); + + res = __hfsplus_getxattr(dentry->d_inode, xattr_name, value, size); + kfree(xattr_name); + return res; + +} + static inline int can_list(const char *xattr_name) { if (!xattr_name) @@ -806,9 +852,6 @@ end_removexattr: static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - char *xattr_name; - int res; - if (!strcmp(name, "")) return -EINVAL; @@ -818,24 +861,19 @@ static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name, */ if (is_known_namespace(name)) return -EOPNOTSUPP; - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN - + XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); - strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); - res = hfsplus_getxattr(dentry, xattr_name, buffer, size); - kfree(xattr_name); - return res; + /* + * osx is the namespace we use to indicate an unprefixed + * attribute on the filesystem (like the ones that OS X + * creates), so we pass the name through unmodified (after + * ensuring it doesn't conflict with another namespace). + */ + return __hfsplus_getxattr(dentry->d_inode, name, buffer, size); } static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags, int type) { - char *xattr_name; - int res; - if (!strcmp(name, "")) return -EINVAL; @@ -845,16 +883,14 @@ static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, */ if (is_known_namespace(name)) return -EOPNOTSUPP; - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN - + XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); - strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); - res = hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); - kfree(xattr_name); - return res; + /* + * osx is the namespace we use to indicate an unprefixed + * attribute on the filesystem (like the ones that OS X + * creates), so we pass the name through unmodified (after + * ensuring it doesn't conflict with another namespace). + */ + return __hfsplus_setxattr(dentry->d_inode, name, buffer, size, flags); } static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list, diff --git a/fs/hfsplus/xattr.h b/fs/hfsplus/xattr.h index 288530cf80b5..f9b0955b3d28 100644 --- a/fs/hfsplus/xattr.h +++ b/fs/hfsplus/xattr.h @@ -21,22 +21,16 @@ extern const struct xattr_handler *hfsplus_xattr_handlers[]; int __hfsplus_setxattr(struct inode *inode, const char *name, const void *value, size_t size, int flags); -static inline int hfsplus_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) -{ - return __hfsplus_setxattr(dentry->d_inode, name, value, size, flags); -} +int hfsplus_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, + const char *prefix, size_t prefixlen); ssize_t __hfsplus_getxattr(struct inode *inode, const char *name, - void *value, size_t size); - -static inline ssize_t hfsplus_getxattr(struct dentry *dentry, - const char *name, - void *value, - size_t size) -{ - return __hfsplus_getxattr(dentry->d_inode, name, value, size); -} + void *value, size_t size); + +ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, + void *value, size_t size, + const char *prefix, size_t prefixlen); ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); diff --git a/fs/hfsplus/xattr_security.c b/fs/hfsplus/xattr_security.c index 6ec5e107691f..aacff00a9ff9 100644 --- a/fs/hfsplus/xattr_security.c +++ b/fs/hfsplus/xattr_security.c @@ -16,43 +16,17 @@ static int hfsplus_security_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - char *xattr_name; - int res; - - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_SECURITY_PREFIX); - strcpy(xattr_name + XATTR_SECURITY_PREFIX_LEN, name); - - res = hfsplus_getxattr(dentry, xattr_name, buffer, size); - kfree(xattr_name); - return res; + return hfsplus_getxattr(dentry, name, buffer, size, + XATTR_SECURITY_PREFIX, + XATTR_SECURITY_PREFIX_LEN); } static int hfsplus_security_setxattr(struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags, int type) { - char *xattr_name; - int res; - - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_SECURITY_PREFIX); - strcpy(xattr_name + XATTR_SECURITY_PREFIX_LEN, name); - - res = hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); - kfree(xattr_name); - return res; + return hfsplus_setxattr(dentry, name, buffer, size, flags, + XATTR_SECURITY_PREFIX, + XATTR_SECURITY_PREFIX_LEN); } static size_t hfsplus_security_listxattr(struct dentry *dentry, char *list, diff --git a/fs/hfsplus/xattr_trusted.c b/fs/hfsplus/xattr_trusted.c index 3c5f27e4746a..bcf65089b7f7 100644 --- a/fs/hfsplus/xattr_trusted.c +++ b/fs/hfsplus/xattr_trusted.c @@ -14,43 +14,16 @@ static int hfsplus_trusted_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - char *xattr_name; - int res; - - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_TRUSTED_PREFIX); - strcpy(xattr_name + XATTR_TRUSTED_PREFIX_LEN, name); - - res = hfsplus_getxattr(dentry, xattr_name, buffer, size); - kfree(xattr_name); - return res; + return hfsplus_getxattr(dentry, name, buffer, size, + XATTR_TRUSTED_PREFIX, + XATTR_TRUSTED_PREFIX_LEN); } static int hfsplus_trusted_setxattr(struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags, int type) { - char *xattr_name; - int res; - - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_TRUSTED_PREFIX); - strcpy(xattr_name + XATTR_TRUSTED_PREFIX_LEN, name); - - res = hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); - kfree(xattr_name); - return res; + return hfsplus_setxattr(dentry, name, buffer, size, flags, + XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); } static size_t hfsplus_trusted_listxattr(struct dentry *dentry, char *list, diff --git a/fs/hfsplus/xattr_user.c b/fs/hfsplus/xattr_user.c index 2b625a538b64..5aa0e6dc4a1e 100644 --- a/fs/hfsplus/xattr_user.c +++ b/fs/hfsplus/xattr_user.c @@ -14,43 +14,16 @@ static int hfsplus_user_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - char *xattr_name; - int res; - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_USER_PREFIX); - strcpy(xattr_name + XATTR_USER_PREFIX_LEN, name); - - res = hfsplus_getxattr(dentry, xattr_name, buffer, size); - kfree(xattr_name); - return res; + return hfsplus_getxattr(dentry, name, buffer, size, + XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); } static int hfsplus_user_setxattr(struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags, int type) { - char *xattr_name; - int res; - - if (!strcmp(name, "")) - return -EINVAL; - - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, - GFP_KERNEL); - if (!xattr_name) - return -ENOMEM; - strcpy(xattr_name, XATTR_USER_PREFIX); - strcpy(xattr_name + XATTR_USER_PREFIX_LEN, name); - - res = hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); - kfree(xattr_name); - return res; + return hfsplus_setxattr(dentry, name, buffer, size, flags, + XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); } static size_t hfsplus_user_listxattr(struct dentry *dentry, char *list, diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 3197aed10614..070dc4b33544 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -330,8 +330,8 @@ static sector_t jfs_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping, block, jfs_get_block); } -static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t jfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -339,13 +339,13 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, jfs_get_block); + ret = blockdev_direct_IO(iocb, inode, iter, offset, jfs_get_block); /* * In case of error extending write may have instantiated a few * blocks outside i_size. Trim these off again. */ - if (unlikely((rw & WRITE) && ret < 0)) { + if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { loff_t isize = i_size_read(inode); loff_t end = offset + count; diff --git a/fs/locks.c b/fs/locks.c index 52b780fb5258..653faabb07f4 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2590,6 +2590,44 @@ static int locks_show(struct seq_file *f, void *v) return 0; } +static void __show_fd_locks(struct seq_file *f, + struct list_head *head, int *id, + struct file *filp, struct files_struct *files) +{ + struct file_lock *fl; + + list_for_each_entry(fl, head, fl_list) { + + if (filp != fl->fl_file) + continue; + if (fl->fl_owner != files && + fl->fl_owner != filp) + continue; + + (*id)++; + seq_puts(f, "lock:\t"); + lock_get_status(f, fl, *id, ""); + } +} + +void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files) +{ + struct inode *inode = file_inode(filp); + struct file_lock_context *ctx; + int id = 0; + + ctx = inode->i_flctx; + if (!ctx) + return; + + spin_lock(&ctx->flc_lock); + __show_fd_locks(f, &ctx->flc_flock, &id, filp, files); + __show_fd_locks(f, &ctx->flc_posix, &id, filp, files); + __show_fd_locks(f, &ctx->flc_lease, &id, filp, files); + spin_unlock(&ctx->flc_lock); +} + static void *locks_start(struct seq_file *f, loff_t *pos) __acquires(&blocked_lock_lock) { diff --git a/fs/namei.c b/fs/namei.c index 76fb76a0818b..ffab2e06e147 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1585,7 +1585,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path, inode = path->dentry->d_inode; } err = -ENOENT; - if (!inode || d_is_negative(path->dentry)) + if (d_is_negative(path->dentry)) goto out_path_put; if (should_follow_link(path->dentry, follow)) { @@ -2310,7 +2310,7 @@ mountpoint_last(struct nameidata *nd, struct path *path) mutex_unlock(&dir->d_inode->i_mutex); done: - if (!dentry->d_inode || d_is_negative(dentry)) { + if (d_is_negative(dentry)) { error = -ENOENT; dput(dentry); goto out; @@ -3038,7 +3038,7 @@ retry_lookup: finish_lookup: /* we _can_ be in RCU mode here */ error = -ENOENT; - if (!inode || d_is_negative(path->dentry)) { + if (d_is_negative(path->dentry)) { path_to_nameidata(path, nd); goto out; } @@ -3077,7 +3077,7 @@ finish_open: error = -ENOTDIR; if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) goto out; - if (!S_ISREG(nd->inode->i_mode)) + if (!d_is_reg(nd->path.dentry)) will_truncate = false; if (will_truncate) { diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 479bf8db264e..011324ce9df2 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -170,20 +170,15 @@ ncp_file_write_iter(struct kiocb *iocb, struct iov_iter *from) struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); size_t already_written = 0; - loff_t pos = iocb->ki_pos; - size_t count = iov_iter_count(from); size_t bufsize; int errno; void *bouncebuffer; + off_t pos; ncp_dbg(1, "enter %pD2\n", file); - errno = generic_write_checks(file, &pos, &count, 0); - if (errno) + errno = generic_write_checks(iocb, from); + if (errno <= 0) return errno; - iov_iter_truncate(from, count); - - if (!count) - return 0; errno = ncp_make_open(inode, O_WRONLY); if (errno) { @@ -201,10 +196,11 @@ ncp_file_write_iter(struct kiocb *iocb, struct iov_iter *from) errno = -EIO; /* -ENOMEM */ goto outrel; } + pos = iocb->ki_pos; while (iov_iter_count(from)) { int written_this_time; size_t to_write = min_t(size_t, - bufsize - ((off_t)pos % bufsize), + bufsize - (pos % bufsize), iov_iter_count(from)); if (copy_from_iter(bouncebuffer, to_write, from) != to_write) { diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index c3929fb2ab26..682f65fe09b5 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -240,7 +240,6 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, /** * nfs_direct_IO - NFS address space operation for direct I/O - * @rw: direction (read or write) * @iocb: target I/O control block * @iov: array of vectors that define I/O buffer * @pos: offset in file to begin the operation @@ -251,7 +250,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, * shunt off direct read and write requests before the VFS gets them, * so this method is only ever called for swap. */ -ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos) +ssize_t nfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t pos) { struct inode *inode = iocb->ki_filp->f_mapping->host; @@ -267,9 +266,9 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t #else VM_BUG_ON(iov_iter_count(iter) != PAGE_SIZE); - if (rw == READ) + if (iov_iter_rw(iter) == READ) return nfs_file_direct_read(iocb, iter, pos); - return nfs_file_direct_write(iocb, iter, pos); + return nfs_file_direct_write(iocb, iter); #endif /* CONFIG_NFS_SWAP */ } @@ -960,8 +959,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, * Note that O_APPEND is not supported for NFS direct writes, as there * is no atomic O_APPEND write facility in the NFS protocol. */ -ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter, - loff_t pos) +ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) { ssize_t result = -EINVAL; struct file *file = iocb->ki_filp; @@ -969,25 +967,16 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter, struct inode *inode = mapping->host; struct nfs_direct_req *dreq; struct nfs_lock_context *l_ctx; - loff_t end; - size_t count = iov_iter_count(iter); - end = (pos + count - 1) >> PAGE_CACHE_SHIFT; - - nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); + loff_t pos, end; dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n", - file, count, (long long) pos); + file, iov_iter_count(iter), (long long) iocb->ki_pos); - result = generic_write_checks(file, &pos, &count, 0); - if (result) - goto out; + nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, + iov_iter_count(iter)); - result = -EINVAL; - if ((ssize_t) count < 0) - goto out; - result = 0; - if (!count) - goto out; + pos = iocb->ki_pos; + end = (pos + iov_iter_count(iter) - 1) >> PAGE_CACHE_SHIFT; mutex_lock(&inode->i_mutex); @@ -1002,7 +991,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter, goto out_unlock; } - task_io_account_write(count); + task_io_account_write(iov_iter_count(iter)); result = -ENOMEM; dreq = nfs_direct_req_alloc(); @@ -1010,7 +999,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter, goto out_unlock; dreq->inode = inode; - dreq->bytes_left = count; + dreq->bytes_left = iov_iter_count(iter); dreq->io_start = pos; dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); l_ctx = nfs_get_lock_context(dreq->ctx); @@ -1050,7 +1039,6 @@ out_release: nfs_direct_req_release(dreq); out_unlock: mutex_unlock(&inode->i_mutex); -out: return result; } diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f6a3adedf027..c40e4363e746 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -170,7 +170,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to) struct inode *inode = file_inode(iocb->ki_filp); ssize_t result; - if (iocb->ki_filp->f_flags & O_DIRECT) + if (iocb->ki_flags & IOCB_DIRECT) return nfs_file_direct_read(iocb, to, iocb->ki_pos); dprintk("NFS: read(%pD2, %zu@%lu)\n", @@ -674,17 +674,20 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) unsigned long written = 0; ssize_t result; size_t count = iov_iter_count(from); - loff_t pos = iocb->ki_pos; result = nfs_key_timeout_notify(file, inode); if (result) return result; - if (file->f_flags & O_DIRECT) - return nfs_file_direct_write(iocb, from, pos); + if (iocb->ki_flags & IOCB_DIRECT) { + result = generic_write_checks(iocb, from); + if (result <= 0) + return result; + return nfs_file_direct_write(iocb, from); + } dprintk("NFS: write(%pD2, %zu@%Ld)\n", - file, count, (long long) pos); + file, count, (long long) iocb->ki_pos); result = -EBUSY; if (IS_SWAPFILE(inode)) @@ -692,7 +695,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) /* * O_APPEND implies that we must revalidate the file length. */ - if (file->f_flags & O_APPEND) { + if (iocb->ki_flags & IOCB_APPEND) { result = nfs_revalidate_file_size(inode, file); if (result) goto out; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 568ecf0a880f..b8f5c63f77b2 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -117,15 +117,15 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, static void nfs_readpage_release(struct nfs_page *req) { - struct inode *d_inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->dentry->d_inode; - dprintk("NFS: read done (%s/%llu %d@%lld)\n", d_inode->i_sb->s_id, - (unsigned long long)NFS_FILEID(d_inode), req->wb_bytes, + dprintk("NFS: read done (%s/%llu %d@%lld)\n", inode->i_sb->s_id, + (unsigned long long)NFS_FILEID(inode), req->wb_bytes, (long long)req_offset(req)); if (nfs_page_group_sync_on_bit(req, PG_UNLOCKPAGE)) { if (PageUptodate(req->wb_page)) - nfs_readpage_to_fscache(d_inode, req->wb_page, 0); + nfs_readpage_to_fscache(inode, req->wb_page, 0); unlock_page(req->wb_page); } diff --git a/fs/nilfs2/alloc.c b/fs/nilfs2/alloc.c index 741fd02e0444..8df0f3b7839b 100644 --- a/fs/nilfs2/alloc.c +++ b/fs/nilfs2/alloc.c @@ -405,13 +405,14 @@ nilfs_palloc_rest_groups_in_desc_block(const struct inode *inode, static int nilfs_palloc_count_desc_blocks(struct inode *inode, unsigned long *desc_blocks) { - unsigned long blknum; + __u64 blknum; int ret; ret = nilfs_bmap_last_key(NILFS_I(inode)->i_bmap, &blknum); if (likely(!ret)) *desc_blocks = DIV_ROUND_UP( - blknum, NILFS_MDT(inode)->mi_blocks_per_desc_block); + (unsigned long)blknum, + NILFS_MDT(inode)->mi_blocks_per_desc_block); return ret; } diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index aadbd0b5e3e8..27f75bcbeb30 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -152,9 +152,7 @@ static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) * * %-EEXIST - A record associated with @key already exist. */ -int nilfs_bmap_insert(struct nilfs_bmap *bmap, - unsigned long key, - unsigned long rec) +int nilfs_bmap_insert(struct nilfs_bmap *bmap, __u64 key, unsigned long rec) { int ret; @@ -191,19 +189,47 @@ static int nilfs_bmap_do_delete(struct nilfs_bmap *bmap, __u64 key) return bmap->b_ops->bop_delete(bmap, key); } -int nilfs_bmap_last_key(struct nilfs_bmap *bmap, unsigned long *key) +/** + * nilfs_bmap_seek_key - seek a valid entry and return its key + * @bmap: bmap struct + * @start: start key number + * @keyp: place to store valid key + * + * Description: nilfs_bmap_seek_key() seeks a valid key on @bmap + * starting from @start, and stores it to @keyp if found. + * + * Return Value: On success, 0 is returned. On error, one of the following + * negative error codes is returned. + * + * %-EIO - I/O error. + * + * %-ENOMEM - Insufficient amount of memory available. + * + * %-ENOENT - No valid entry was found + */ +int nilfs_bmap_seek_key(struct nilfs_bmap *bmap, __u64 start, __u64 *keyp) { - __u64 lastkey; int ret; down_read(&bmap->b_sem); - ret = bmap->b_ops->bop_last_key(bmap, &lastkey); + ret = bmap->b_ops->bop_seek_key(bmap, start, keyp); + up_read(&bmap->b_sem); + + if (ret < 0) + ret = nilfs_bmap_convert_error(bmap, __func__, ret); + return ret; +} + +int nilfs_bmap_last_key(struct nilfs_bmap *bmap, __u64 *keyp) +{ + int ret; + + down_read(&bmap->b_sem); + ret = bmap->b_ops->bop_last_key(bmap, keyp); up_read(&bmap->b_sem); if (ret < 0) ret = nilfs_bmap_convert_error(bmap, __func__, ret); - else - *key = lastkey; return ret; } @@ -224,7 +250,7 @@ int nilfs_bmap_last_key(struct nilfs_bmap *bmap, unsigned long *key) * * %-ENOENT - A record associated with @key does not exist. */ -int nilfs_bmap_delete(struct nilfs_bmap *bmap, unsigned long key) +int nilfs_bmap_delete(struct nilfs_bmap *bmap, __u64 key) { int ret; @@ -235,7 +261,7 @@ int nilfs_bmap_delete(struct nilfs_bmap *bmap, unsigned long key) return nilfs_bmap_convert_error(bmap, __func__, ret); } -static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, unsigned long key) +static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, __u64 key) { __u64 lastkey; int ret; @@ -276,7 +302,7 @@ static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, unsigned long key) * * %-ENOMEM - Insufficient amount of memory available. */ -int nilfs_bmap_truncate(struct nilfs_bmap *bmap, unsigned long key) +int nilfs_bmap_truncate(struct nilfs_bmap *bmap, __u64 key) { int ret; diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index b89e68076adc..bfa817ce40b3 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -76,8 +76,10 @@ struct nilfs_bmap_operations { union nilfs_binfo *); int (*bop_mark)(struct nilfs_bmap *, __u64, int); - /* The following functions are internal use only. */ + int (*bop_seek_key)(const struct nilfs_bmap *, __u64, __u64 *); int (*bop_last_key)(const struct nilfs_bmap *, __u64 *); + + /* The following functions are internal use only. */ int (*bop_check_insert)(const struct nilfs_bmap *, __u64); int (*bop_check_delete)(struct nilfs_bmap *, __u64); int (*bop_gather_data)(struct nilfs_bmap *, __u64 *, __u64 *, int); @@ -153,10 +155,11 @@ int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *); int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *); void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *); int nilfs_bmap_lookup_contig(struct nilfs_bmap *, __u64, __u64 *, unsigned); -int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long); -int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long); -int nilfs_bmap_last_key(struct nilfs_bmap *, unsigned long *); -int nilfs_bmap_truncate(struct nilfs_bmap *, unsigned long); +int nilfs_bmap_insert(struct nilfs_bmap *bmap, __u64 key, unsigned long rec); +int nilfs_bmap_delete(struct nilfs_bmap *bmap, __u64 key); +int nilfs_bmap_seek_key(struct nilfs_bmap *bmap, __u64 start, __u64 *keyp); +int nilfs_bmap_last_key(struct nilfs_bmap *bmap, __u64 *keyp); +int nilfs_bmap_truncate(struct nilfs_bmap *bmap, __u64 key); void nilfs_bmap_clear(struct nilfs_bmap *); int nilfs_bmap_propagate(struct nilfs_bmap *, struct buffer_head *); void nilfs_bmap_lookup_dirty_buffers(struct nilfs_bmap *, struct list_head *); diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index ecdbae19a766..059f37137f9a 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -633,6 +633,44 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_bmap *btree, return 0; } +/** + * nilfs_btree_get_next_key - get next valid key from btree path array + * @btree: bmap struct of btree + * @path: array of nilfs_btree_path struct + * @minlevel: start level + * @nextkey: place to store the next valid key + * + * Return Value: If a next key was found, 0 is returned. Otherwise, + * -ENOENT is returned. + */ +static int nilfs_btree_get_next_key(const struct nilfs_bmap *btree, + const struct nilfs_btree_path *path, + int minlevel, __u64 *nextkey) +{ + struct nilfs_btree_node *node; + int maxlevel = nilfs_btree_height(btree) - 1; + int index, next_adj, level; + + /* Next index is already set to bp_index for leaf nodes. */ + next_adj = 0; + for (level = minlevel; level <= maxlevel; level++) { + if (level == maxlevel) + node = nilfs_btree_get_root(btree); + else + node = nilfs_btree_get_nonroot_node(path, level); + + index = path[level].bp_index + next_adj; + if (index < nilfs_btree_node_get_nchildren(node)) { + /* Next key is in this node */ + *nextkey = nilfs_btree_node_get_key(node, index); + return 0; + } + /* For non-leaf nodes, next index is stored at bp_index + 1. */ + next_adj = 1; + } + return -ENOENT; +} + static int nilfs_btree_lookup(const struct nilfs_bmap *btree, __u64 key, int level, __u64 *ptrp) { @@ -1563,6 +1601,27 @@ out: return ret; } +static int nilfs_btree_seek_key(const struct nilfs_bmap *btree, __u64 start, + __u64 *keyp) +{ + struct nilfs_btree_path *path; + const int minlevel = NILFS_BTREE_LEVEL_NODE_MIN; + int ret; + + path = nilfs_btree_alloc_path(); + if (!path) + return -ENOMEM; + + ret = nilfs_btree_do_lookup(btree, path, start, NULL, minlevel, 0); + if (!ret) + *keyp = start; + else if (ret == -ENOENT) + ret = nilfs_btree_get_next_key(btree, path, minlevel, keyp); + + nilfs_btree_free_path(path); + return ret; +} + static int nilfs_btree_last_key(const struct nilfs_bmap *btree, __u64 *keyp) { struct nilfs_btree_path *path; @@ -2298,7 +2357,9 @@ static const struct nilfs_bmap_operations nilfs_btree_ops = { .bop_assign = nilfs_btree_assign, .bop_mark = nilfs_btree_mark, + .bop_seek_key = nilfs_btree_seek_key, .bop_last_key = nilfs_btree_last_key, + .bop_check_insert = NULL, .bop_check_delete = nilfs_btree_check_delete, .bop_gather_data = nilfs_btree_gather_data, @@ -2318,7 +2379,9 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = { .bop_assign = nilfs_btree_assign_gc, .bop_mark = NULL, + .bop_seek_key = NULL, .bop_last_key = NULL, + .bop_check_insert = NULL, .bop_check_delete = NULL, .bop_gather_data = NULL, diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 0d58075f34e2..b6596cab9e99 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c @@ -53,6 +53,13 @@ nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno) return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile)); } +static __u64 nilfs_cpfile_first_checkpoint_in_block(const struct inode *cpfile, + unsigned long blkoff) +{ + return (__u64)nilfs_cpfile_checkpoints_per_block(cpfile) * blkoff + + 1 - NILFS_MDT(cpfile)->mi_first_entry_offset; +} + static unsigned long nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile, __u64 curr, @@ -146,6 +153,44 @@ static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile, create, nilfs_cpfile_block_init, bhp); } +/** + * nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile + * @cpfile: inode of cpfile + * @start_cno: start checkpoint number (inclusive) + * @end_cno: end checkpoint number (inclusive) + * @cnop: place to store the next checkpoint number + * @bhp: place to store a pointer to buffer_head struct + * + * Return Value: On success, it returns 0. On error, the following negative + * error code is returned. + * + * %-ENOMEM - Insufficient memory available. + * + * %-EIO - I/O error + * + * %-ENOENT - no block exists in the range. + */ +static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile, + __u64 start_cno, __u64 end_cno, + __u64 *cnop, + struct buffer_head **bhp) +{ + unsigned long start, end, blkoff; + int ret; + + if (unlikely(start_cno > end_cno)) + return -ENOENT; + + start = nilfs_cpfile_get_blkoff(cpfile, start_cno); + end = nilfs_cpfile_get_blkoff(cpfile, end_cno); + + ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp); + if (!ret) + *cnop = (blkoff == start) ? start_cno : + nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff); + return ret; +} + static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile, __u64 cno) { @@ -403,14 +448,15 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, return -ENOENT; /* checkpoint number 0 is invalid */ down_read(&NILFS_MDT(cpfile)->mi_sem); - for (n = 0; cno < cur_cno && n < nci; cno += ncps) { - ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno); - ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh); + for (n = 0; n < nci; cno += ncps) { + ret = nilfs_cpfile_find_checkpoint_block( + cpfile, cno, cur_cno - 1, &cno, &bh); if (ret < 0) { - if (ret != -ENOENT) - goto out; - continue; /* skip hole */ + if (likely(ret == -ENOENT)) + break; + goto out; } + ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno); kaddr = kmap_atomic(bh->b_page); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index 82f4865e86dd..ebf89fd8ac1a 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c @@ -173,6 +173,21 @@ static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key) return ret; } +static int nilfs_direct_seek_key(const struct nilfs_bmap *direct, __u64 start, + __u64 *keyp) +{ + __u64 key; + + for (key = start; key <= NILFS_DIRECT_KEY_MAX; key++) { + if (nilfs_direct_get_ptr(direct, key) != + NILFS_BMAP_INVALID_PTR) { + *keyp = key; + return 0; + } + } + return -ENOENT; +} + static int nilfs_direct_last_key(const struct nilfs_bmap *direct, __u64 *keyp) { __u64 key, lastkey; @@ -355,7 +370,9 @@ static const struct nilfs_bmap_operations nilfs_direct_ops = { .bop_assign = nilfs_direct_assign, .bop_mark = NULL, + .bop_seek_key = nilfs_direct_seek_key, .bop_last_key = nilfs_direct_last_key, + .bop_check_insert = nilfs_direct_check_insert, .bop_check_delete = NULL, .bop_gather_data = nilfs_direct_gather_data, diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index ab4987bc637f..be936df4ba73 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -106,7 +106,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, err = nilfs_transaction_begin(inode->i_sb, &ti, 1); if (unlikely(err)) goto out; - err = nilfs_bmap_insert(ii->i_bmap, (unsigned long)blkoff, + err = nilfs_bmap_insert(ii->i_bmap, blkoff, (unsigned long)bh_result); if (unlikely(err != 0)) { if (err == -EEXIST) { @@ -305,8 +305,7 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping, } static ssize_t -nilfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) +nilfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -314,18 +313,17 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, size_t count = iov_iter_count(iter); ssize_t size; - if (rw == WRITE) + if (iov_iter_rw(iter) == WRITE) return 0; /* Needs synchronization with the cleaner */ - size = blockdev_direct_IO(rw, iocb, inode, iter, offset, - nilfs_get_block); + size = blockdev_direct_IO(iocb, inode, iter, offset, nilfs_get_block); /* * In case of error extending write may have instantiated a few * blocks outside i_size. Trim these off again. */ - if (unlikely((rw & WRITE) && size < 0)) { + if (unlikely(iov_iter_rw(iter) == WRITE && size < 0)) { loff_t isize = i_size_read(inode); loff_t end = offset + count; @@ -443,21 +441,20 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) void nilfs_set_inode_flags(struct inode *inode) { unsigned int flags = NILFS_I(inode)->i_flags; + unsigned int new_fl = 0; - inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | - S_DIRSYNC); if (flags & FS_SYNC_FL) - inode->i_flags |= S_SYNC; + new_fl |= S_SYNC; if (flags & FS_APPEND_FL) - inode->i_flags |= S_APPEND; + new_fl |= S_APPEND; if (flags & FS_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; + new_fl |= S_IMMUTABLE; if (flags & FS_NOATIME_FL) - inode->i_flags |= S_NOATIME; + new_fl |= S_NOATIME; if (flags & FS_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; - mapping_set_gfp_mask(inode->i_mapping, - mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); + new_fl |= S_DIRSYNC; + inode_set_flags(inode, new_fl, S_SYNC | S_APPEND | S_IMMUTABLE | + S_NOATIME | S_DIRSYNC); } int nilfs_read_inode_common(struct inode *inode, @@ -542,6 +539,8 @@ static int __nilfs_read_inode(struct super_block *sb, brelse(bh); up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); nilfs_set_inode_flags(inode); + mapping_set_gfp_mask(inode->i_mapping, + mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); return 0; failed_unmap: @@ -714,7 +713,7 @@ void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh, int flags) static void nilfs_truncate_bmap(struct nilfs_inode_info *ii, unsigned long from) { - unsigned long b; + __u64 b; int ret; if (!test_bit(NILFS_I_BMAP, &ii->i_state)) @@ -729,7 +728,7 @@ repeat: if (b < from) return; - b -= min_t(unsigned long, NILFS_MAX_TRUNCATE_BLOCKS, b - from); + b -= min_t(__u64, NILFS_MAX_TRUNCATE_BLOCKS, b - from); ret = nilfs_bmap_truncate(ii->i_bmap, b); nilfs_relax_pressure_in_lock(ii->vfs_inode.i_sb); if (!ret || (ret == -ENOMEM && diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 892cf5ffdb8e..dee34d990281 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -261,6 +261,60 @@ int nilfs_mdt_get_block(struct inode *inode, unsigned long blkoff, int create, } /** + * nilfs_mdt_find_block - find and get a buffer on meta data file. + * @inode: inode of the meta data file + * @start: start block offset (inclusive) + * @end: end block offset (inclusive) + * @blkoff: block offset + * @out_bh: place to store a pointer to buffer_head struct + * + * nilfs_mdt_find_block() looks up an existing block in range of + * [@start, @end] and stores pointer to a buffer head of the block to + * @out_bh, and block offset to @blkoff, respectively. @out_bh and + * @blkoff are substituted only when zero is returned. + * + * Return Value: On success, it returns 0. On error, the following negative + * error code is returned. + * + * %-ENOMEM - Insufficient memory available. + * + * %-EIO - I/O error + * + * %-ENOENT - no block was found in the range + */ +int nilfs_mdt_find_block(struct inode *inode, unsigned long start, + unsigned long end, unsigned long *blkoff, + struct buffer_head **out_bh) +{ + __u64 next; + int ret; + + if (unlikely(start > end)) + return -ENOENT; + + ret = nilfs_mdt_read_block(inode, start, true, out_bh); + if (!ret) { + *blkoff = start; + goto out; + } + if (unlikely(ret != -ENOENT || start == ULONG_MAX)) + goto out; + + ret = nilfs_bmap_seek_key(NILFS_I(inode)->i_bmap, start + 1, &next); + if (!ret) { + if (next <= end) { + ret = nilfs_mdt_read_block(inode, next, true, out_bh); + if (!ret) + *blkoff = next; + } else { + ret = -ENOENT; + } + } +out: + return ret; +} + +/** * nilfs_mdt_delete_block - make a hole on the meta data file. * @inode: inode of the meta data file * @block: block offset diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index ab172e8549c5..fe529a87a208 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h @@ -78,6 +78,9 @@ int nilfs_mdt_get_block(struct inode *, unsigned long, int, void (*init_block)(struct inode *, struct buffer_head *, void *), struct buffer_head **); +int nilfs_mdt_find_block(struct inode *inode, unsigned long start, + unsigned long end, unsigned long *blkoff, + struct buffer_head **out_bh); int nilfs_mdt_delete_block(struct inode *, unsigned long); int nilfs_mdt_forget_block(struct inode *, unsigned long); int nilfs_mdt_mark_block_dirty(struct inode *, unsigned long); @@ -111,7 +114,10 @@ static inline __u64 nilfs_mdt_cno(struct inode *inode) return ((struct the_nilfs *)inode->i_sb->s_fs_info)->ns_cno; } -#define nilfs_mdt_bgl_lock(inode, bg) \ - (&NILFS_MDT(inode)->mi_bgl->locks[(bg) & (NR_BG_LOCKS-1)].lock) +static inline spinlock_t * +nilfs_mdt_bgl_lock(struct inode *inode, unsigned int block_group) +{ + return bgl_lock_ptr(NILFS_MDT(inode)->mi_bgl, block_group); +} #endif /* _NILFS_MDT_H */ diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index 700ecbcca55d..45d650addd56 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c @@ -89,18 +89,16 @@ struct buffer_head *nilfs_grab_buffer(struct inode *inode, void nilfs_forget_buffer(struct buffer_head *bh) { struct page *page = bh->b_page; + const unsigned long clear_bits = + (1 << BH_Uptodate | 1 << BH_Dirty | 1 << BH_Mapped | + 1 << BH_Async_Write | 1 << BH_NILFS_Volatile | + 1 << BH_NILFS_Checked | 1 << BH_NILFS_Redirected); lock_buffer(bh); - clear_buffer_nilfs_volatile(bh); - clear_buffer_nilfs_checked(bh); - clear_buffer_nilfs_redirected(bh); - clear_buffer_async_write(bh); - clear_buffer_dirty(bh); + set_mask_bits(&bh->b_state, clear_bits, 0); if (nilfs_page_buffers_clean(page)) __nilfs_clear_page_dirty(page); - clear_buffer_uptodate(bh); - clear_buffer_mapped(bh); bh->b_blocknr = -1; ClearPageUptodate(page); ClearPageMappedToDisk(page); @@ -421,6 +419,10 @@ void nilfs_clear_dirty_page(struct page *page, bool silent) if (page_has_buffers(page)) { struct buffer_head *bh, *head; + const unsigned long clear_bits = + (1 << BH_Uptodate | 1 << BH_Dirty | 1 << BH_Mapped | + 1 << BH_Async_Write | 1 << BH_NILFS_Volatile | + 1 << BH_NILFS_Checked | 1 << BH_NILFS_Redirected); bh = head = page_buffers(page); do { @@ -430,13 +432,7 @@ void nilfs_clear_dirty_page(struct page *page, bool silent) "discard block %llu, size %zu", (u64)bh->b_blocknr, bh->b_size); } - clear_buffer_async_write(bh); - clear_buffer_dirty(bh); - clear_buffer_nilfs_volatile(bh); - clear_buffer_nilfs_checked(bh); - clear_buffer_nilfs_redirected(bh); - clear_buffer_uptodate(bh); - clear_buffer_mapped(bh); + set_mask_bits(&bh->b_state, clear_bits, 0); unlock_buffer(bh); } while (bh = bh->b_this_page, bh != head); } diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 0c3f303baf32..c6abbad9b8e3 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -24,6 +24,7 @@ #include <linux/pagemap.h> #include <linux/buffer_head.h> #include <linux/writeback.h> +#include <linux/bitops.h> #include <linux/bio.h> #include <linux/completion.h> #include <linux/blkdev.h> @@ -1588,7 +1589,6 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci) list_for_each_entry(bh, &segbuf->sb_segsum_buffers, b_assoc_buffers) { - set_buffer_async_write(bh); if (bh->b_page != bd_page) { if (bd_page) { lock_page(bd_page); @@ -1688,7 +1688,6 @@ static void nilfs_abort_logs(struct list_head *logs, int err) list_for_each_entry(segbuf, logs, sb_list) { list_for_each_entry(bh, &segbuf->sb_segsum_buffers, b_assoc_buffers) { - clear_buffer_async_write(bh); if (bh->b_page != bd_page) { if (bd_page) end_page_writeback(bd_page); @@ -1768,7 +1767,6 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) b_assoc_buffers) { set_buffer_uptodate(bh); clear_buffer_dirty(bh); - clear_buffer_async_write(bh); if (bh->b_page != bd_page) { if (bd_page) end_page_writeback(bd_page); @@ -1788,12 +1786,13 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) */ list_for_each_entry(bh, &segbuf->sb_payload_buffers, b_assoc_buffers) { - set_buffer_uptodate(bh); - clear_buffer_dirty(bh); - clear_buffer_async_write(bh); - clear_buffer_delay(bh); - clear_buffer_nilfs_volatile(bh); - clear_buffer_nilfs_redirected(bh); + const unsigned long set_bits = (1 << BH_Uptodate); + const unsigned long clear_bits = + (1 << BH_Dirty | 1 << BH_Async_Write | + 1 << BH_Delay | 1 << BH_NILFS_Volatile | + 1 << BH_NILFS_Redirected); + + set_mask_bits(&bh->b_state, clear_bits, set_bits); if (bh == segbuf->sb_super_root) { if (bh->b_page != bd_page) { end_page_writeback(bd_page); diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 5bc2a1cf73c3..c1725f20a9d1 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -1020,7 +1020,7 @@ int nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno) struct dentry *dentry; int ret; - if (cno < 0 || cno > nilfs->ns_cno) + if (cno > nilfs->ns_cno) return false; if (cno >= nilfs_last_cno(nilfs)) diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 840e95e3f1d2..7bb487e663b4 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -328,25 +328,25 @@ err_out: return err; } -static ssize_t ntfs_prepare_file_for_write(struct file *file, loff_t *ppos, - size_t *count) +static ssize_t ntfs_prepare_file_for_write(struct kiocb *iocb, + struct iov_iter *from) { loff_t pos; s64 end, ll; ssize_t err; unsigned long flags; + struct file *file = iocb->ki_filp; struct inode *vi = file_inode(file); ntfs_inode *base_ni, *ni = NTFS_I(vi); ntfs_volume *vol = ni->vol; ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, pos " - "0x%llx, count 0x%lx.", vi->i_ino, + "0x%llx, count 0x%zx.", vi->i_ino, (unsigned)le32_to_cpu(ni->type), - (unsigned long long)*ppos, (unsigned long)*count); - /* We can write back this queue in page reclaim. */ - current->backing_dev_info = inode_to_bdi(vi); - err = generic_write_checks(file, ppos, count, S_ISBLK(vi->i_mode)); - if (unlikely(err)) + (unsigned long long)iocb->ki_pos, + iov_iter_count(from)); + err = generic_write_checks(iocb, from); + if (unlikely(err <= 0)) goto out; /* * All checks have passed. Before we start doing any writing we want @@ -379,8 +379,6 @@ static ssize_t ntfs_prepare_file_for_write(struct file *file, loff_t *ppos, err = -EOPNOTSUPP; goto out; } - if (*count == 0) - goto out; base_ni = ni; if (NInoAttr(ni)) base_ni = ni->ext.base_ntfs_ino; @@ -392,9 +390,9 @@ static ssize_t ntfs_prepare_file_for_write(struct file *file, loff_t *ppos, * cannot fail either so there is no need to check the return code. */ file_update_time(file); - pos = *ppos; + pos = iocb->ki_pos; /* The first byte after the last cluster being written to. */ - end = (pos + *count + vol->cluster_size_mask) & + end = (pos + iov_iter_count(from) + vol->cluster_size_mask) & ~(u64)vol->cluster_size_mask; /* * If the write goes beyond the allocated size, extend the allocation @@ -422,7 +420,7 @@ static ssize_t ntfs_prepare_file_for_write(struct file *file, loff_t *ppos, "partially extended.", vi->i_ino, (unsigned) le32_to_cpu(ni->type)); - *count = ll - pos; + iov_iter_truncate(from, ll - pos); } } else { err = ll; @@ -438,7 +436,7 @@ static ssize_t ntfs_prepare_file_for_write(struct file *file, loff_t *ppos, vi->i_ino, (unsigned) le32_to_cpu(ni->type), (int)-err); - *count = ll - pos; + iov_iter_truncate(from, ll - pos); } else { if (err != -ENOSPC) ntfs_error(vi->i_sb, "Cannot perform " @@ -1930,60 +1928,36 @@ again: } /** - * ntfs_file_write_iter_nolock - write data to a file - * @iocb: IO state structure (file, offset, etc.) - * @from: iov_iter with data to write - * - * Basically the same as __generic_file_write_iter() except that it ends - * up calling ntfs_perform_write() instead of generic_perform_write() and that - * O_DIRECT is not implemented. - */ -static ssize_t ntfs_file_write_iter_nolock(struct kiocb *iocb, - struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - loff_t pos = iocb->ki_pos; - ssize_t written = 0; - ssize_t err; - size_t count = iov_iter_count(from); - - err = ntfs_prepare_file_for_write(file, &pos, &count); - if (count && !err) { - iov_iter_truncate(from, count); - written = ntfs_perform_write(file, from, pos); - if (likely(written >= 0)) - iocb->ki_pos = pos + written; - } - current->backing_dev_info = NULL; - return written ? written : err; -} - -/** * ntfs_file_write_iter - simple wrapper for ntfs_file_write_iter_nolock() * @iocb: IO state structure * @from: iov_iter with data to write * * Basically the same as generic_file_write_iter() except that it ends up - * calling ntfs_file_write_iter_nolock() instead of - * __generic_file_write_iter(). + * up calling ntfs_perform_write() instead of generic_perform_write() and that + * O_DIRECT is not implemented. */ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *vi = file_inode(file); - ssize_t ret; + ssize_t written = 0; + ssize_t err; mutex_lock(&vi->i_mutex); - ret = ntfs_file_write_iter_nolock(iocb, from); + /* We can write back this queue in page reclaim. */ + current->backing_dev_info = inode_to_bdi(vi); + err = ntfs_prepare_file_for_write(iocb, from); + if (iov_iter_count(from) && !err) + written = ntfs_perform_write(file, from, iocb->ki_pos); + current->backing_dev_info = NULL; mutex_unlock(&vi->i_mutex); - if (ret > 0) { - ssize_t err; - - err = generic_write_sync(file, iocb->ki_pos - ret, ret); + if (likely(written > 0)) { + err = generic_write_sync(file, iocb->ki_pos, written); if (err < 0) - ret = err; + written = 0; } - return ret; + iocb->ki_pos += written; + return written ? written : err; } /** diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 8d2bc840c288..f906a250da6a 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -855,10 +855,9 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, ocfs2_inode_unlock(inode, 1); } - written = __blockdev_direct_IO(WRITE, iocb, inode, inode->i_sb->s_bdev, - iter, offset, - ocfs2_direct_IO_get_blocks, - ocfs2_dio_end_io, NULL, 0); + written = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, + offset, ocfs2_direct_IO_get_blocks, + ocfs2_dio_end_io, NULL, 0); if (unlikely(written < 0)) { loff_t i_size = i_size_read(inode); @@ -946,9 +945,7 @@ out: return ret; } -static ssize_t ocfs2_direct_IO(int rw, - struct kiocb *iocb, - struct iov_iter *iter, +static ssize_t ocfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; @@ -970,12 +967,11 @@ static ssize_t ocfs2_direct_IO(int rw, if (i_size_read(inode) <= offset && !full_coherency) return 0; - if (rw == READ) - return __blockdev_direct_IO(rw, iocb, inode, - inode->i_sb->s_bdev, - iter, offset, - ocfs2_direct_IO_get_blocks, - ocfs2_dio_end_io, NULL, 0); + if (iov_iter_rw(iter) == READ) + return __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, + iter, offset, + ocfs2_direct_IO_get_blocks, + ocfs2_dio_end_io, NULL, 0); else return ocfs2_direct_IO_write(iocb, iter, offset); } diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 8c48e989beba..913fc250d85a 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2106,7 +2106,7 @@ out: } static int ocfs2_prepare_inode_for_write(struct file *file, - loff_t *ppos, + loff_t pos, size_t count, int appending, int *direct_io, @@ -2115,7 +2115,7 @@ static int ocfs2_prepare_inode_for_write(struct file *file, int ret = 0, meta_level = 0; struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; - loff_t saved_pos = 0, end; + loff_t end; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); int full_coherency = !(osb->s_mount_opt & OCFS2_MOUNT_COHERENCY_BUFFERED); @@ -2155,23 +2155,16 @@ static int ocfs2_prepare_inode_for_write(struct file *file, } } - /* work on a copy of ppos until we're sure that we won't have - * to recalculate it due to relocking. */ - if (appending) - saved_pos = i_size_read(inode); - else - saved_pos = *ppos; - - end = saved_pos + count; + end = pos + count; - ret = ocfs2_check_range_for_refcount(inode, saved_pos, count); + ret = ocfs2_check_range_for_refcount(inode, pos, count); if (ret == 1) { ocfs2_inode_unlock(inode, meta_level); meta_level = -1; ret = ocfs2_prepare_inode_for_refcount(inode, file, - saved_pos, + pos, count, &meta_level); if (has_refcount) @@ -2227,7 +2220,7 @@ static int ocfs2_prepare_inode_for_write(struct file *file, * caller will have to retake some cluster * locks and initiate the io as buffered. */ - ret = ocfs2_check_range_for_holes(inode, saved_pos, count); + ret = ocfs2_check_range_for_holes(inode, pos, count); if (ret == 1) { /* * Fallback to old way if the feature bit is not set. @@ -2242,12 +2235,9 @@ static int ocfs2_prepare_inode_for_write(struct file *file, break; } - if (appending) - *ppos = saved_pos; - out_unlock: trace_ocfs2_prepare_inode_for_write(OCFS2_I(inode)->ip_blkno, - saved_pos, appending, count, + pos, appending, count, direct_io, has_refcount); if (meta_level >= 0) @@ -2260,19 +2250,20 @@ out: static ssize_t ocfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { - int ret, direct_io, appending, rw_level, have_alloc_sem = 0; + int direct_io, appending, rw_level, have_alloc_sem = 0; int can_do_direct, has_refcount = 0; ssize_t written = 0; - size_t count = iov_iter_count(from); - loff_t old_size, *ppos = &iocb->ki_pos; + ssize_t ret; + size_t count = iov_iter_count(from), orig_count; + loff_t old_size; u32 old_clusters; struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); - struct address_space *mapping = file->f_mapping; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); int full_coherency = !(osb->s_mount_opt & OCFS2_MOUNT_COHERENCY_BUFFERED); int unaligned_dio = 0; + int dropped_dio = 0; trace_ocfs2_file_aio_write(inode, file, file->f_path.dentry, (unsigned long long)OCFS2_I(inode)->ip_blkno, @@ -2283,8 +2274,8 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb, if (count == 0) return 0; - appending = file->f_flags & O_APPEND ? 1 : 0; - direct_io = file->f_flags & O_DIRECT ? 1 : 0; + appending = iocb->ki_flags & IOCB_APPEND ? 1 : 0; + direct_io = iocb->ki_flags & IOCB_DIRECT ? 1 : 0; mutex_lock(&inode->i_mutex); @@ -2329,8 +2320,17 @@ relock: ocfs2_inode_unlock(inode, 1); } + orig_count = iov_iter_count(from); + ret = generic_write_checks(iocb, from); + if (ret <= 0) { + if (ret) + mlog_errno(ret); + goto out; + } + count = ret; + can_do_direct = direct_io; - ret = ocfs2_prepare_inode_for_write(file, ppos, count, appending, + ret = ocfs2_prepare_inode_for_write(file, iocb->ki_pos, count, appending, &can_do_direct, &has_refcount); if (ret < 0) { mlog_errno(ret); @@ -2338,7 +2338,7 @@ relock: } if (direct_io && !is_sync_kiocb(iocb)) - unaligned_dio = ocfs2_is_io_unaligned(inode, count, *ppos); + unaligned_dio = ocfs2_is_io_unaligned(inode, count, iocb->ki_pos); /* * We can't complete the direct I/O as requested, fall back to @@ -2351,6 +2351,9 @@ relock: rw_level = -1; direct_io = 0; + iocb->ki_flags &= ~IOCB_DIRECT; + iov_iter_reexpand(from, orig_count); + dropped_dio = 1; goto relock; } @@ -2374,74 +2377,15 @@ relock: /* communicate with ocfs2_dio_end_io */ ocfs2_iocb_set_rw_locked(iocb, rw_level); - ret = generic_write_checks(file, ppos, &count, - S_ISBLK(inode->i_mode)); - if (ret) - goto out_dio; - - iov_iter_truncate(from, count); - if (direct_io) { - loff_t endbyte; - ssize_t written_buffered; - written = generic_file_direct_write(iocb, from, *ppos); - if (written < 0 || written == count) { - ret = written; - goto out_dio; - } - - /* - * for completing the rest of the request. - */ - count -= written; - written_buffered = generic_perform_write(file, from, *ppos); - /* - * If generic_file_buffered_write() returned a synchronous error - * then we want to return the number of bytes which were - * direct-written, or the error code if that was zero. Note - * that this differs from normal direct-io semantics, which - * will return -EFOO even if some bytes were written. - */ - if (written_buffered < 0) { - ret = written_buffered; - goto out_dio; - } - - /* We need to ensure that the page cache pages are written to - * disk and invalidated to preserve the expected O_DIRECT - * semantics. - */ - endbyte = *ppos + written_buffered - 1; - ret = filemap_write_and_wait_range(file->f_mapping, *ppos, - endbyte); - if (ret == 0) { - iocb->ki_pos = *ppos + written_buffered; - written += written_buffered; - invalidate_mapping_pages(mapping, - *ppos >> PAGE_CACHE_SHIFT, - endbyte >> PAGE_CACHE_SHIFT); - } else { - /* - * We don't know how much we wrote, so just return - * the number of bytes which were direct-written - */ - } - } else { - current->backing_dev_info = inode_to_bdi(inode); - written = generic_perform_write(file, from, *ppos); - if (likely(written >= 0)) - iocb->ki_pos = *ppos + written; - current->backing_dev_info = NULL; - } - -out_dio: + written = __generic_file_write_iter(iocb, from); /* buffered aio wouldn't have proper lock coverage today */ - BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT)); + BUG_ON(written == -EIOCBQUEUED && !(iocb->ki_flags & IOCB_DIRECT)); if (unlikely(written <= 0)) goto no_sync; - if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) || - ((file->f_flags & O_DIRECT) && !direct_io)) { + if (((file->f_flags & O_DSYNC) && !direct_io) || + IS_SYNC(inode) || dropped_dio) { ret = filemap_fdatawrite_range(file->f_mapping, iocb->ki_pos - written, iocb->ki_pos - 1); @@ -2552,7 +2496,7 @@ static ssize_t ocfs2_file_read_iter(struct kiocb *iocb, * buffered reads protect themselves in ->readpage(). O_DIRECT reads * need locks to protect pending reads from racing with truncate. */ - if (filp->f_flags & O_DIRECT) { + if (iocb->ki_flags & IOCB_DIRECT) { have_alloc_sem = 1; ocfs2_iocb_set_sem_locked(iocb); @@ -2586,7 +2530,7 @@ static ssize_t ocfs2_file_read_iter(struct kiocb *iocb, trace_generic_file_aio_read_ret(ret); /* buffered aio wouldn't have proper lock coverage today */ - BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT)); + BUG_ON(ret == -EIOCBQUEUED && !(iocb->ki_flags & IOCB_DIRECT)); /* see ocfs2_file_write_iter */ if (ret == -EIOCBQUEUED || !ocfs2_iocb_is_rw_locked(iocb)) { diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 8e5ad83b629a..af84ad04df77 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -8,6 +8,7 @@ #include <linux/security.h> #include <linux/file.h> #include <linux/seq_file.h> +#include <linux/fs.h> #include <linux/proc_fs.h> @@ -48,17 +49,23 @@ static int seq_show(struct seq_file *m, void *v) put_files_struct(files); } - if (!ret) { - seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n", - (long long)file->f_pos, f_flags, - real_mount(file->f_path.mnt)->mnt_id); - if (file->f_op->show_fdinfo) - file->f_op->show_fdinfo(m, file); - ret = seq_has_overflowed(m); - fput(file); - } + if (ret) + return ret; - return ret; + seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n", + (long long)file->f_pos, f_flags, + real_mount(file->f_path.mnt)->mnt_id); + + show_fd_locks(m, file, files); + if (seq_has_overflowed(m)) + goto out; + + if (file->f_op->show_fdinfo) + file->f_op->show_fdinfo(m, file); + +out: + fput(file); + return 0; } static int seq_fdinfo_open(struct inode *inode, struct file *file) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 0ccd4ba3a246..ecc25cf0ee6e 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -900,14 +900,17 @@ static inline struct dquot **i_dquot(struct inode *inode) static int dqinit_needed(struct inode *inode, int type) { + struct dquot * const *dquots; int cnt; if (IS_NOQUOTA(inode)) return 0; + + dquots = i_dquot(inode); if (type != -1) - return !i_dquot(inode)[type]; + return !dquots[type]; for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (!i_dquot(inode)[cnt]) + if (!dquots[cnt]) return 1; return 0; } @@ -970,12 +973,13 @@ static void add_dquot_ref(struct super_block *sb, int type) static void remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head) { - struct dquot *dquot = i_dquot(inode)[type]; + struct dquot **dquots = i_dquot(inode); + struct dquot *dquot = dquots[type]; - i_dquot(inode)[type] = NULL; if (!dquot) return; + dquots[type] = NULL; if (list_empty(&dquot->dq_free)) { /* * The inode still has reference to dquot so it can't be in the @@ -1159,8 +1163,8 @@ static int need_print_warning(struct dquot_warn *warn) return uid_eq(current_fsuid(), warn->w_dq_id.uid); case GRPQUOTA: return in_group_p(warn->w_dq_id.gid); - case PRJQUOTA: /* Never taken... Just make gcc happy */ - return 0; + case PRJQUOTA: + return 1; } return 0; } @@ -1389,16 +1393,21 @@ static int dquot_active(const struct inode *inode) static void __dquot_initialize(struct inode *inode, int type) { int cnt, init_needed = 0; - struct dquot *got[MAXQUOTAS]; + struct dquot **dquots, *got[MAXQUOTAS]; struct super_block *sb = inode->i_sb; qsize_t rsv; if (!dquot_active(inode)) return; + dquots = i_dquot(inode); + /* First get references to structures we might need. */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { struct kqid qid; + kprojid_t projid; + int rc; + got[cnt] = NULL; if (type != -1 && cnt != type) continue; @@ -1407,8 +1416,12 @@ static void __dquot_initialize(struct inode *inode, int type) * we check it without locking here to avoid unnecessary * dqget()/dqput() calls. */ - if (i_dquot(inode)[cnt]) + if (dquots[cnt]) + continue; + + if (!sb_has_quota_active(sb, cnt)) continue; + init_needed = 1; switch (cnt) { @@ -1418,6 +1431,12 @@ static void __dquot_initialize(struct inode *inode, int type) case GRPQUOTA: qid = make_kqid_gid(inode->i_gid); break; + case PRJQUOTA: + rc = inode->i_sb->dq_op->get_projid(inode, &projid); + if (rc) + continue; + qid = make_kqid_projid(projid); + break; } got[cnt] = dqget(sb, qid); } @@ -1438,8 +1457,8 @@ static void __dquot_initialize(struct inode *inode, int type) /* We could race with quotaon or dqget() could have failed */ if (!got[cnt]) continue; - if (!i_dquot(inode)[cnt]) { - i_dquot(inode)[cnt] = got[cnt]; + if (!dquots[cnt]) { + dquots[cnt] = got[cnt]; got[cnt] = NULL; /* * Make quota reservation system happy if someone @@ -1447,7 +1466,7 @@ static void __dquot_initialize(struct inode *inode, int type) */ rsv = inode_get_rsv_space(inode); if (unlikely(rsv)) - dquot_resv_space(i_dquot(inode)[cnt], rsv); + dquot_resv_space(dquots[cnt], rsv); } } out_err: @@ -1473,12 +1492,13 @@ EXPORT_SYMBOL(dquot_initialize); static void __dquot_drop(struct inode *inode) { int cnt; + struct dquot **dquots = i_dquot(inode); struct dquot *put[MAXQUOTAS]; spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - put[cnt] = i_dquot(inode)[cnt]; - i_dquot(inode)[cnt] = NULL; + put[cnt] = dquots[cnt]; + dquots[cnt] = NULL; } spin_unlock(&dq_data_lock); dqput_all(put); @@ -1486,6 +1506,7 @@ static void __dquot_drop(struct inode *inode) void dquot_drop(struct inode *inode) { + struct dquot * const *dquots; int cnt; if (IS_NOQUOTA(inode)) @@ -1498,8 +1519,9 @@ void dquot_drop(struct inode *inode) * must assure that nobody can come after the DQUOT_DROP and * add quota pointers back anyway. */ + dquots = i_dquot(inode); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (i_dquot(inode)[cnt]) + if (dquots[cnt]) break; } @@ -1600,8 +1622,8 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) { int cnt, ret = 0, index; struct dquot_warn warn[MAXQUOTAS]; - struct dquot **dquots = i_dquot(inode); int reserve = flags & DQUOT_SPACE_RESERVE; + struct dquot **dquots; if (!dquot_active(inode)) { inode_incr_space(inode, number, reserve); @@ -1611,6 +1633,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) for (cnt = 0; cnt < MAXQUOTAS; cnt++) warn[cnt].w_type = QUOTA_NL_NOWARN; + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -1652,13 +1675,14 @@ int dquot_alloc_inode(struct inode *inode) { int cnt, ret = 0, index; struct dquot_warn warn[MAXQUOTAS]; - struct dquot * const *dquots = i_dquot(inode); + struct dquot * const *dquots; if (!dquot_active(inode)) return 0; for (cnt = 0; cnt < MAXQUOTAS; cnt++) warn[cnt].w_type = QUOTA_NL_NOWARN; + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -1690,6 +1714,7 @@ EXPORT_SYMBOL(dquot_alloc_inode); */ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) { + struct dquot **dquots; int cnt, index; if (!dquot_active(inode)) { @@ -1697,18 +1722,18 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) return 0; } + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); /* Claim reserved quotas to allocated quotas */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (i_dquot(inode)[cnt]) - dquot_claim_reserved_space(i_dquot(inode)[cnt], - number); + if (dquots[cnt]) + dquot_claim_reserved_space(dquots[cnt], number); } /* Update inode bytes */ inode_claim_rsv_space(inode, number); spin_unlock(&dq_data_lock); - mark_all_dquot_dirty(i_dquot(inode)); + mark_all_dquot_dirty(dquots); srcu_read_unlock(&dquot_srcu, index); return 0; } @@ -1719,6 +1744,7 @@ EXPORT_SYMBOL(dquot_claim_space_nodirty); */ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) { + struct dquot **dquots; int cnt, index; if (!dquot_active(inode)) { @@ -1726,18 +1752,18 @@ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) return; } + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); /* Claim reserved quotas to allocated quotas */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (i_dquot(inode)[cnt]) - dquot_reclaim_reserved_space(i_dquot(inode)[cnt], - number); + if (dquots[cnt]) + dquot_reclaim_reserved_space(dquots[cnt], number); } /* Update inode bytes */ inode_reclaim_rsv_space(inode, number); spin_unlock(&dq_data_lock); - mark_all_dquot_dirty(i_dquot(inode)); + mark_all_dquot_dirty(dquots); srcu_read_unlock(&dquot_srcu, index); return; } @@ -1750,7 +1776,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags) { unsigned int cnt; struct dquot_warn warn[MAXQUOTAS]; - struct dquot **dquots = i_dquot(inode); + struct dquot **dquots; int reserve = flags & DQUOT_SPACE_RESERVE, index; if (!dquot_active(inode)) { @@ -1758,6 +1784,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags) return; } + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -1793,12 +1820,13 @@ void dquot_free_inode(struct inode *inode) { unsigned int cnt; struct dquot_warn warn[MAXQUOTAS]; - struct dquot * const *dquots = i_dquot(inode); + struct dquot * const *dquots; int index; if (!dquot_active(inode)) return; + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -2161,7 +2189,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, error = -EROFS; goto out_fmt; } - if (!sb->s_op->quota_write || !sb->s_op->quota_read) { + if (!sb->s_op->quota_write || !sb->s_op->quota_read || + (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) { error = -EINVAL; goto out_fmt; } @@ -2614,55 +2643,73 @@ out: EXPORT_SYMBOL(dquot_set_dqblk); /* Generic routine for getting common part of quota file information */ -int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +int dquot_get_state(struct super_block *sb, struct qc_state *state) { struct mem_dqinfo *mi; + struct qc_type_state *tstate; + struct quota_info *dqopt = sb_dqopt(sb); + int type; mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); - if (!sb_has_quota_active(sb, type)) { - mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); - return -ESRCH; + memset(state, 0, sizeof(*state)); + for (type = 0; type < MAXQUOTAS; type++) { + if (!sb_has_quota_active(sb, type)) + continue; + tstate = state->s_state + type; + mi = sb_dqopt(sb)->info + type; + tstate->flags = QCI_ACCT_ENABLED; + spin_lock(&dq_data_lock); + if (mi->dqi_flags & DQF_SYS_FILE) + tstate->flags |= QCI_SYSFILE; + if (mi->dqi_flags & DQF_ROOT_SQUASH) + tstate->flags |= QCI_ROOT_SQUASH; + if (sb_has_quota_limits_enabled(sb, type)) + tstate->flags |= QCI_LIMITS_ENFORCED; + tstate->spc_timelimit = mi->dqi_bgrace; + tstate->ino_timelimit = mi->dqi_igrace; + tstate->ino = dqopt->files[type]->i_ino; + tstate->blocks = dqopt->files[type]->i_blocks; + tstate->nextents = 1; /* We don't know... */ + spin_unlock(&dq_data_lock); } - mi = sb_dqopt(sb)->info + type; - spin_lock(&dq_data_lock); - ii->dqi_bgrace = mi->dqi_bgrace; - ii->dqi_igrace = mi->dqi_igrace; - ii->dqi_flags = mi->dqi_flags & DQF_GETINFO_MASK; - ii->dqi_valid = IIF_ALL; - spin_unlock(&dq_data_lock); mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); return 0; } -EXPORT_SYMBOL(dquot_get_dqinfo); +EXPORT_SYMBOL(dquot_get_state); /* Generic routine for setting common part of quota file information */ -int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii) { struct mem_dqinfo *mi; int err = 0; + if ((ii->i_fieldmask & QC_WARNS_MASK) || + (ii->i_fieldmask & QC_RT_SPC_TIMER)) + return -EINVAL; mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); if (!sb_has_quota_active(sb, type)) { err = -ESRCH; goto out; } mi = sb_dqopt(sb)->info + type; - if (ii->dqi_valid & IIF_FLAGS) { - if (ii->dqi_flags & ~DQF_SETINFO_MASK || - (ii->dqi_flags & DQF_ROOT_SQUASH && + if (ii->i_fieldmask & QC_FLAGS) { + if ((ii->i_flags & QCI_ROOT_SQUASH && mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) { err = -EINVAL; goto out; } } spin_lock(&dq_data_lock); - if (ii->dqi_valid & IIF_BGRACE) - mi->dqi_bgrace = ii->dqi_bgrace; - if (ii->dqi_valid & IIF_IGRACE) - mi->dqi_igrace = ii->dqi_igrace; - if (ii->dqi_valid & IIF_FLAGS) - mi->dqi_flags = (mi->dqi_flags & ~DQF_SETINFO_MASK) | - (ii->dqi_flags & DQF_SETINFO_MASK); + if (ii->i_fieldmask & QC_SPC_TIMER) + mi->dqi_bgrace = ii->i_spc_timelimit; + if (ii->i_fieldmask & QC_INO_TIMER) + mi->dqi_igrace = ii->i_ino_timelimit; + if (ii->i_fieldmask & QC_FLAGS) { + if (ii->i_flags & QCI_ROOT_SQUASH) + mi->dqi_flags |= DQF_ROOT_SQUASH; + else + mi->dqi_flags &= ~DQF_ROOT_SQUASH; + } spin_unlock(&dq_data_lock); mark_info_dirty(sb, type); /* Force write to disk */ @@ -2677,7 +2724,7 @@ const struct quotactl_ops dquot_quotactl_ops = { .quota_on = dquot_quota_on, .quota_off = dquot_quota_off, .quota_sync = dquot_quota_sync, - .get_info = dquot_get_dqinfo, + .get_state = dquot_get_state, .set_info = dquot_set_dqinfo, .get_dqblk = dquot_get_dqblk, .set_dqblk = dquot_set_dqblk @@ -2688,7 +2735,7 @@ const struct quotactl_ops dquot_quotactl_sysfile_ops = { .quota_enable = dquot_quota_enable, .quota_disable = dquot_quota_disable, .quota_sync = dquot_quota_sync, - .get_info = dquot_get_dqinfo, + .get_state = dquot_get_state, .set_info = dquot_set_dqinfo, .get_dqblk = dquot_get_dqblk, .set_dqblk = dquot_set_dqblk diff --git a/fs/quota/quota.c b/fs/quota/quota.c index d14a799c7785..86ded7375c21 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -118,13 +118,30 @@ static int quota_getfmt(struct super_block *sb, int type, void __user *addr) static int quota_getinfo(struct super_block *sb, int type, void __user *addr) { - struct if_dqinfo info; + struct qc_state state; + struct qc_type_state *tstate; + struct if_dqinfo uinfo; int ret; - if (!sb->s_qcop->get_info) + /* This checks whether qc_state has enough entries... */ + BUILD_BUG_ON(MAXQUOTAS > XQM_MAXQUOTAS); + if (!sb->s_qcop->get_state) return -ENOSYS; - ret = sb->s_qcop->get_info(sb, type, &info); - if (!ret && copy_to_user(addr, &info, sizeof(info))) + ret = sb->s_qcop->get_state(sb, &state); + if (ret) + return ret; + tstate = state.s_state + type; + if (!(tstate->flags & QCI_ACCT_ENABLED)) + return -ESRCH; + memset(&uinfo, 0, sizeof(uinfo)); + uinfo.dqi_bgrace = tstate->spc_timelimit; + uinfo.dqi_igrace = tstate->ino_timelimit; + if (tstate->flags & QCI_SYSFILE) + uinfo.dqi_flags |= DQF_SYS_FILE; + if (tstate->flags & QCI_ROOT_SQUASH) + uinfo.dqi_flags |= DQF_ROOT_SQUASH; + uinfo.dqi_valid = IIF_ALL; + if (!ret && copy_to_user(addr, &uinfo, sizeof(uinfo))) return -EFAULT; return ret; } @@ -132,12 +149,31 @@ static int quota_getinfo(struct super_block *sb, int type, void __user *addr) static int quota_setinfo(struct super_block *sb, int type, void __user *addr) { struct if_dqinfo info; + struct qc_info qinfo; if (copy_from_user(&info, addr, sizeof(info))) return -EFAULT; if (!sb->s_qcop->set_info) return -ENOSYS; - return sb->s_qcop->set_info(sb, type, &info); + if (info.dqi_valid & ~(IIF_FLAGS | IIF_BGRACE | IIF_IGRACE)) + return -EINVAL; + memset(&qinfo, 0, sizeof(qinfo)); + if (info.dqi_valid & IIF_FLAGS) { + if (info.dqi_flags & ~DQF_SETINFO_MASK) + return -EINVAL; + if (info.dqi_flags & DQF_ROOT_SQUASH) + qinfo.i_flags |= QCI_ROOT_SQUASH; + qinfo.i_fieldmask |= QC_FLAGS; + } + if (info.dqi_valid & IIF_BGRACE) { + qinfo.i_spc_timelimit = info.dqi_bgrace; + qinfo.i_fieldmask |= QC_SPC_TIMER; + } + if (info.dqi_valid & IIF_IGRACE) { + qinfo.i_ino_timelimit = info.dqi_igrace; + qinfo.i_fieldmask |= QC_INO_TIMER; + } + return sb->s_qcop->set_info(sb, type, &qinfo); } static inline qsize_t qbtos(qsize_t blocks) @@ -252,25 +288,149 @@ static int quota_disable(struct super_block *sb, void __user *addr) return sb->s_qcop->quota_disable(sb, flags); } +static int quota_state_to_flags(struct qc_state *state) +{ + int flags = 0; + + if (state->s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) + flags |= FS_QUOTA_UDQ_ACCT; + if (state->s_state[USRQUOTA].flags & QCI_LIMITS_ENFORCED) + flags |= FS_QUOTA_UDQ_ENFD; + if (state->s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) + flags |= FS_QUOTA_GDQ_ACCT; + if (state->s_state[GRPQUOTA].flags & QCI_LIMITS_ENFORCED) + flags |= FS_QUOTA_GDQ_ENFD; + if (state->s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) + flags |= FS_QUOTA_PDQ_ACCT; + if (state->s_state[PRJQUOTA].flags & QCI_LIMITS_ENFORCED) + flags |= FS_QUOTA_PDQ_ENFD; + return flags; +} + +static int quota_getstate(struct super_block *sb, struct fs_quota_stat *fqs) +{ + int type; + struct qc_state state; + int ret; + + ret = sb->s_qcop->get_state(sb, &state); + if (ret < 0) + return ret; + + memset(fqs, 0, sizeof(*fqs)); + fqs->qs_version = FS_QSTAT_VERSION; + fqs->qs_flags = quota_state_to_flags(&state); + /* No quota enabled? */ + if (!fqs->qs_flags) + return -ENOSYS; + fqs->qs_incoredqs = state.s_incoredqs; + /* + * GETXSTATE quotactl has space for just one set of time limits so + * report them for the first enabled quota type + */ + for (type = 0; type < XQM_MAXQUOTAS; type++) + if (state.s_state[type].flags & QCI_ACCT_ENABLED) + break; + BUG_ON(type == XQM_MAXQUOTAS); + fqs->qs_btimelimit = state.s_state[type].spc_timelimit; + fqs->qs_itimelimit = state.s_state[type].ino_timelimit; + fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit; + fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit; + fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit; + if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) { + fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino; + fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks; + fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents; + } + if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) { + fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino; + fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks; + fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents; + } + if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) { + /* + * Q_XGETQSTAT doesn't have room for both group and project + * quotas. So, allow the project quota values to be copied out + * only if there is no group quota information available. + */ + if (!(state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED)) { + fqs->qs_gquota.qfs_ino = state.s_state[PRJQUOTA].ino; + fqs->qs_gquota.qfs_nblks = + state.s_state[PRJQUOTA].blocks; + fqs->qs_gquota.qfs_nextents = + state.s_state[PRJQUOTA].nextents; + } + } + return 0; +} + static int quota_getxstate(struct super_block *sb, void __user *addr) { struct fs_quota_stat fqs; int ret; - if (!sb->s_qcop->get_xstate) + if (!sb->s_qcop->get_state) return -ENOSYS; - ret = sb->s_qcop->get_xstate(sb, &fqs); + ret = quota_getstate(sb, &fqs); if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) return -EFAULT; return ret; } +static int quota_getstatev(struct super_block *sb, struct fs_quota_statv *fqs) +{ + int type; + struct qc_state state; + int ret; + + ret = sb->s_qcop->get_state(sb, &state); + if (ret < 0) + return ret; + + memset(fqs, 0, sizeof(*fqs)); + fqs->qs_version = FS_QSTAT_VERSION; + fqs->qs_flags = quota_state_to_flags(&state); + /* No quota enabled? */ + if (!fqs->qs_flags) + return -ENOSYS; + fqs->qs_incoredqs = state.s_incoredqs; + /* + * GETXSTATV quotactl has space for just one set of time limits so + * report them for the first enabled quota type + */ + for (type = 0; type < XQM_MAXQUOTAS; type++) + if (state.s_state[type].flags & QCI_ACCT_ENABLED) + break; + BUG_ON(type == XQM_MAXQUOTAS); + fqs->qs_btimelimit = state.s_state[type].spc_timelimit; + fqs->qs_itimelimit = state.s_state[type].ino_timelimit; + fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit; + fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit; + fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit; + if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) { + fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino; + fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks; + fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents; + } + if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) { + fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino; + fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks; + fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents; + } + if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) { + fqs->qs_pquota.qfs_ino = state.s_state[PRJQUOTA].ino; + fqs->qs_pquota.qfs_nblks = state.s_state[PRJQUOTA].blocks; + fqs->qs_pquota.qfs_nextents = state.s_state[PRJQUOTA].nextents; + } + return 0; +} + static int quota_getxstatev(struct super_block *sb, void __user *addr) { struct fs_quota_statv fqs; int ret; - if (!sb->s_qcop->get_xstatev) + if (!sb->s_qcop->get_state) return -ENOSYS; memset(&fqs, 0, sizeof(fqs)); @@ -284,7 +444,7 @@ static int quota_getxstatev(struct super_block *sb, void __user *addr) default: return -EINVAL; } - ret = sb->s_qcop->get_xstatev(sb, &fqs); + ret = quota_getstatev(sb, &fqs); if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) return -EFAULT; return ret; @@ -357,6 +517,30 @@ static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src) dst->d_fieldmask |= QC_RT_SPACE; } +static void copy_qcinfo_from_xfs_dqblk(struct qc_info *dst, + struct fs_disk_quota *src) +{ + memset(dst, 0, sizeof(*dst)); + dst->i_spc_timelimit = src->d_btimer; + dst->i_ino_timelimit = src->d_itimer; + dst->i_rt_spc_timelimit = src->d_rtbtimer; + dst->i_ino_warnlimit = src->d_iwarns; + dst->i_spc_warnlimit = src->d_bwarns; + dst->i_rt_spc_warnlimit = src->d_rtbwarns; + if (src->d_fieldmask & FS_DQ_BWARNS) + dst->i_fieldmask |= QC_SPC_WARNS; + if (src->d_fieldmask & FS_DQ_IWARNS) + dst->i_fieldmask |= QC_INO_WARNS; + if (src->d_fieldmask & FS_DQ_RTBWARNS) + dst->i_fieldmask |= QC_RT_SPC_WARNS; + if (src->d_fieldmask & FS_DQ_BTIMER) + dst->i_fieldmask |= QC_SPC_TIMER; + if (src->d_fieldmask & FS_DQ_ITIMER) + dst->i_fieldmask |= QC_INO_TIMER; + if (src->d_fieldmask & FS_DQ_RTBTIMER) + dst->i_fieldmask |= QC_RT_SPC_TIMER; +} + static int quota_setxquota(struct super_block *sb, int type, qid_t id, void __user *addr) { @@ -371,6 +555,21 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id, qid = make_kqid(current_user_ns(), type, id); if (!qid_valid(qid)) return -EINVAL; + /* Are we actually setting timer / warning limits for all users? */ + if (from_kqid(&init_user_ns, qid) == 0 && + fdq.d_fieldmask & (FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK)) { + struct qc_info qinfo; + int ret; + + if (!sb->s_qcop->set_info) + return -EINVAL; + copy_qcinfo_from_xfs_dqblk(&qinfo, &fdq); + ret = sb->s_qcop->set_info(sb, type, &qinfo); + if (ret) + return ret; + /* These are already done */ + fdq.d_fieldmask &= ~(FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK); + } copy_from_xfs_dqblk(&qdq, &fdq); return sb->s_qcop->set_dqblk(sb, qid, &qdq); } diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c index d65877fbe8f4..58efb83dec1c 100644 --- a/fs/quota/quota_tree.c +++ b/fs/quota/quota_tree.c @@ -349,6 +349,13 @@ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot) { int tmp = QT_TREEOFF; + +#ifdef __QUOTA_QT_PARANOIA + if (info->dqi_blocks <= QT_TREEOFF) { + quota_error(dquot->dq_sb, "Quota tree root isn't allocated!"); + return -EIO; + } +#endif return do_insert_tree(info, dquot, &tmp, 0); } diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 9cb10d7197f7..2aa012a68e90 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -117,12 +117,16 @@ static int v2_read_file_info(struct super_block *sb, int type) qinfo = info->dqi_priv; if (version == 0) { /* limits are stored as unsigned 32-bit data */ - info->dqi_max_spc_limit = 0xffffffffULL << QUOTABLOCK_BITS; + info->dqi_max_spc_limit = 0xffffffffLL << QUOTABLOCK_BITS; info->dqi_max_ino_limit = 0xffffffff; } else { - /* used space is stored as unsigned 64-bit value in bytes */ - info->dqi_max_spc_limit = 0xffffffffffffffffULL; /* 2^64-1 */ - info->dqi_max_ino_limit = 0xffffffffffffffffULL; + /* + * Used space is stored as unsigned 64-bit value in bytes but + * quota core supports only signed 64-bit values so use that + * as a limit + */ + info->dqi_max_spc_limit = 0x7fffffffffffffffLL; /* 2^63-1 */ + info->dqi_max_ino_limit = 0x7fffffffffffffffLL; } info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); diff --git a/fs/quota/quotaio_v2.h b/fs/quota/quotaio_v2.h index f1966b42c2fd..4e95430093d9 100644 --- a/fs/quota/quotaio_v2.h +++ b/fs/quota/quotaio_v2.h @@ -13,12 +13,14 @@ */ #define V2_INITQMAGICS {\ 0xd9c01f11, /* USRQUOTA */\ - 0xd9c01927 /* GRPQUOTA */\ + 0xd9c01927, /* GRPQUOTA */\ + 0xd9c03f14, /* PRJQUOTA */\ } #define V2_INITQVERSIONS {\ 1, /* USRQUOTA */\ - 1 /* GRPQUOTA */\ + 1, /* GRPQUOTA */\ + 1, /* PRJQUOTA */\ } /* First generic header */ diff --git a/fs/read_write.c b/fs/read_write.c index 45d583c33879..819ef3faf1bb 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -477,7 +477,8 @@ static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t ret = filp->f_op->write_iter(&kiocb, &iter); BUG_ON(ret == -EIOCBQUEUED); - *ppos = kiocb.ki_pos; + if (ret > 0) + *ppos = kiocb.ki_pos; return ret; } diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 9312b7842e03..742242b60972 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -3278,22 +3278,22 @@ static int reiserfs_releasepage(struct page *page, gfp_t unused_gfp_flags) * We thank Mingming Cao for helping us understand in great detail what * to do in this section of the code. */ -static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, loff_t offset) +static ssize_t reiserfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, + ret = blockdev_direct_IO(iocb, inode, iter, offset, reiserfs_get_blocks_direct_io); /* * In case of error extending write may have instantiated a few * blocks outside i_size. Trim these off again. */ - if (unlikely((rw & WRITE) && ret < 0)) { + if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { loff_t isize = i_size_read(inode); loff_t end = offset + count; diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h index bb79cddf0a1f..2adcde137c3f 100644 --- a/fs/reiserfs/reiserfs.h +++ b/fs/reiserfs/reiserfs.h @@ -910,7 +910,6 @@ do { \ if (!(cond)) \ reiserfs_panic(NULL, "assertion failure", "(" #cond ") at " \ __FILE__ ":%i:%s: " format "\n", \ - in_interrupt() ? -1 : task_pid_nr(current), \ __LINE__, __func__ , ##args); \ } while (0) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 71fbbe3e2dab..68b5f182984e 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -805,7 +805,7 @@ static const struct quotactl_ops reiserfs_qctl_operations = { .quota_on = reiserfs_quota_on, .quota_off = dquot_quota_off, .quota_sync = dquot_quota_sync, - .get_info = dquot_get_dqinfo, + .get_state = dquot_get_state, .set_info = dquot_set_dqinfo, .get_dqblk = dquot_get_dqblk, .set_dqblk = dquot_set_dqblk, diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 1ba2baaf4367..6d6a96b4e73f 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -21,7 +21,6 @@ #include "udfdecl.h" -#include <linux/buffer_head.h> #include <linux/bitops.h> #include "udf_i.h" @@ -63,15 +62,14 @@ static int __load_block_bitmap(struct super_block *sb, block_group, nr_groups); } - if (bitmap->s_block_bitmap[block_group]) { + if (bitmap->s_block_bitmap[block_group]) return block_group; - } else { - retval = read_block_bitmap(sb, bitmap, block_group, - block_group); - if (retval < 0) - return retval; - return block_group; - } + + retval = read_block_bitmap(sb, bitmap, block_group, block_group); + if (retval < 0) + return retval; + + return block_group; } static inline int load_block_bitmap(struct super_block *sb, @@ -358,7 +356,6 @@ static void udf_table_free_blocks(struct super_block *sb, struct kernel_lb_addr eloc; struct extent_position oepos, epos; int8_t etype; - int i; struct udf_inode_info *iinfo; mutex_lock(&sbi->s_alloc_mutex); @@ -425,7 +422,6 @@ static void udf_table_free_blocks(struct super_block *sb, } if (epos.bh != oepos.bh) { - i = -1; oepos.block = epos.block; brelse(oepos.bh); get_bh(epos.bh); @@ -762,7 +758,7 @@ inline int udf_prealloc_blocks(struct super_block *sb, uint32_t block_count) { struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; - sector_t allocated; + int allocated; if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) allocated = udf_bitmap_prealloc_blocks(sb, diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 05e90edd1992..541a12b5792d 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c @@ -30,7 +30,6 @@ #include <linux/errno.h> #include <linux/mm.h> #include <linux/slab.h> -#include <linux/buffer_head.h> #include "udf_i.h" #include "udf_sb.h" diff --git a/fs/udf/directory.c b/fs/udf/directory.c index 3e44f575fb9c..c763fda257bf 100644 --- a/fs/udf/directory.c +++ b/fs/udf/directory.c @@ -16,7 +16,6 @@ #include <linux/fs.h> #include <linux/string.h> -#include <linux/buffer_head.h> struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos, struct udf_fileident_bh *fibh, diff --git a/fs/udf/file.c b/fs/udf/file.c index 74050bff64f4..5dadad9960b9 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -33,7 +33,6 @@ #include <linux/capability.h> #include <linux/errno.h> #include <linux/pagemap.h> -#include <linux/buffer_head.h> #include <linux/uio.h> #include "udf_i.h" @@ -100,8 +99,7 @@ static int udf_adinicb_write_begin(struct file *file, return 0; } -static ssize_t udf_adinicb_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, +static ssize_t udf_adinicb_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { /* Fallback to buffered I/O. */ @@ -121,21 +119,21 @@ static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ssize_t retval; struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); - int err, pos; - size_t count = iov_iter_count(from); struct udf_inode_info *iinfo = UDF_I(inode); + int err; mutex_lock(&inode->i_mutex); + + retval = generic_write_checks(iocb, from); + if (retval <= 0) + goto out; + down_write(&iinfo->i_data_sem); if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { - if (file->f_flags & O_APPEND) - pos = inode->i_size; - else - pos = iocb->ki_pos; + loff_t end = iocb->ki_pos + iov_iter_count(from); if (inode->i_sb->s_blocksize < - (udf_file_entry_alloc_offset(inode) + - pos + count)) { + (udf_file_entry_alloc_offset(inode) + end)) { err = udf_expand_file_adinicb(inode); if (err) { mutex_unlock(&inode->i_mutex); @@ -143,16 +141,14 @@ static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from) return err; } } else { - if (pos + count > inode->i_size) - iinfo->i_lenAlloc = pos + count; - else - iinfo->i_lenAlloc = inode->i_size; + iinfo->i_lenAlloc = max(end, inode->i_size); up_write(&iinfo->i_data_sem); } } else up_write(&iinfo->i_data_sem); retval = __generic_file_write_iter(iocb, from); +out: mutex_unlock(&inode->i_mutex); if (retval > 0) { diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 9c1fbd23913d..6afac3d561ac 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -33,7 +33,6 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/pagemap.h> -#include <linux/buffer_head.h> #include <linux/writeback.h> #include <linux/slab.h> #include <linux/crc-itu-t.h> @@ -215,8 +214,7 @@ static int udf_write_begin(struct file *file, struct address_space *mapping, return ret; } -static ssize_t udf_direct_IO(int rw, struct kiocb *iocb, - struct iov_iter *iter, +static ssize_t udf_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; @@ -225,8 +223,8 @@ static ssize_t udf_direct_IO(int rw, struct kiocb *iocb, size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, udf_get_block); - if (unlikely(ret < 0 && (rw & WRITE))) + ret = blockdev_direct_IO(iocb, inode, iter, offset, udf_get_block); + if (unlikely(ret < 0 && iov_iter_rw(iter) == WRITE)) udf_write_failed(mapping, offset + count); return ret; } @@ -1637,7 +1635,7 @@ static int udf_update_inode(struct inode *inode, int do_sync) udf_get_lb_pblock(inode->i_sb, &iinfo->i_location, 0)); if (!bh) { udf_debug("getblk failure\n"); - return -ENOMEM; + return -EIO; } lock_buffer(bh); diff --git a/fs/udf/misc.c b/fs/udf/misc.c index c175b4dabc14..71d1c25f360d 100644 --- a/fs/udf/misc.c +++ b/fs/udf/misc.c @@ -23,7 +23,6 @@ #include <linux/fs.h> #include <linux/string.h> -#include <linux/buffer_head.h> #include <linux/crc-itu-t.h> #include "udf_i.h" diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 33b246b82c98..39661977c89c 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -27,7 +27,6 @@ #include <linux/errno.h> #include <linux/mm.h> #include <linux/slab.h> -#include <linux/buffer_head.h> #include <linux/sched.h> #include <linux/crc-itu-t.h> #include <linux/exportfs.h> @@ -569,8 +568,8 @@ static int udf_add_nondir(struct dentry *dentry, struct inode *inode) *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL); udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); - if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) - mark_inode_dirty(dir); + dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb); + mark_inode_dirty(dir); if (fibh.sbh != fibh.ebh) brelse(fibh.ebh); brelse(fibh.sbh); @@ -683,6 +682,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY; udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); inc_nlink(dir); + dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb); mark_inode_dirty(dir); unlock_new_inode(inode); d_instantiate(dentry, inode); @@ -1024,6 +1024,8 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir, inc_nlink(inode); inode->i_ctime = current_fs_time(inode->i_sb); mark_inode_dirty(inode); + dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb); + mark_inode_dirty(dir); ihold(inode); d_instantiate(dentry, inode); @@ -1127,7 +1129,9 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry, inode_dec_link_count(new_inode); } old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb); + new_dir->i_ctime = new_dir->i_mtime = current_fs_time(new_dir->i_sb); mark_inode_dirty(old_dir); + mark_inode_dirty(new_dir); if (dir_fi) { dir_fi->icb.extLocation = cpu_to_lelb(UDF_I(new_dir)->i_location); diff --git a/fs/udf/partition.c b/fs/udf/partition.c index d6caf01a2097..5f861ed287c3 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c @@ -24,7 +24,6 @@ #include <linux/fs.h> #include <linux/string.h> -#include <linux/buffer_head.h> #include <linux/mutex.h> uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, diff --git a/fs/udf/super.c b/fs/udf/super.c index f169411c4ea0..6299f341967b 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -48,7 +48,6 @@ #include <linux/stat.h> #include <linux/cdrom.h> #include <linux/nls.h> -#include <linux/buffer_head.h> #include <linux/vfs.h> #include <linux/vmalloc.h> #include <linux/errno.h> diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index ac10ca939f26..8dfbc4025e2f 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -27,7 +27,6 @@ #include <linux/mm.h> #include <linux/stat.h> #include <linux/pagemap.h> -#include <linux/buffer_head.h> #include "udf_i.h" static int udf_pc_to_char(struct super_block *sb, unsigned char *from, diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index 8a9657d7f7c6..42b8c57795cb 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -22,7 +22,6 @@ #include "udfdecl.h" #include <linux/fs.h> #include <linux/mm.h> -#include <linux/buffer_head.h> #include "udf_i.h" #include "udf_sb.h" diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 4f8cdc59bc38..1d8eef9cf0f5 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -1495,7 +1495,6 @@ xfs_end_io_direct_write( STATIC ssize_t xfs_vm_direct_IO( - int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t offset) @@ -1503,15 +1502,14 @@ xfs_vm_direct_IO( struct inode *inode = iocb->ki_filp->f_mapping->host; struct block_device *bdev = xfs_find_bdev_for_inode(inode); - if (rw & WRITE) { - return __blockdev_direct_IO(rw, iocb, inode, bdev, iter, - offset, xfs_get_blocks_direct, + if (iov_iter_rw(iter) == WRITE) { + return __blockdev_direct_IO(iocb, inode, bdev, iter, offset, + xfs_get_blocks_direct, xfs_end_io_direct_write, NULL, DIO_ASYNC_EXTEND); } - return __blockdev_direct_IO(rw, iocb, inode, bdev, iter, - offset, xfs_get_blocks_direct, - NULL, NULL, 0); + return __blockdev_direct_IO(iocb, inode, bdev, iter, offset, + xfs_get_blocks_direct, NULL, NULL, 0); } /* diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 44856c3b9617..1f12ad0a8585 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -279,7 +279,7 @@ xfs_file_read_iter( XFS_STATS_INC(xs_read_calls); - if (unlikely(file->f_flags & O_DIRECT)) + if (unlikely(iocb->ki_flags & IOCB_DIRECT)) ioflags |= XFS_IO_ISDIRECT; if (file->f_mode & FMODE_NOCMTIME) ioflags |= XFS_IO_INVIS; @@ -544,18 +544,19 @@ xfs_zero_eof( */ STATIC ssize_t xfs_file_aio_write_checks( - struct file *file, - loff_t *pos, - size_t *count, + struct kiocb *iocb, + struct iov_iter *from, int *iolock) { + struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; struct xfs_inode *ip = XFS_I(inode); - int error = 0; + ssize_t error = 0; + size_t count = iov_iter_count(from); restart: - error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode)); - if (error) + error = generic_write_checks(iocb, from); + if (error <= 0) return error; error = xfs_break_layouts(inode, iolock); @@ -569,16 +570,17 @@ restart: * iolock shared, we need to update it to exclusive which implies * having to redo all checks before. */ - if (*pos > i_size_read(inode)) { + if (iocb->ki_pos > i_size_read(inode)) { bool zero = false; if (*iolock == XFS_IOLOCK_SHARED) { xfs_rw_iunlock(ip, *iolock); *iolock = XFS_IOLOCK_EXCL; xfs_rw_ilock(ip, *iolock); + iov_iter_reexpand(from, count); goto restart; } - error = xfs_zero_eof(ip, *pos, i_size_read(inode), &zero); + error = xfs_zero_eof(ip, iocb->ki_pos, i_size_read(inode), &zero); if (error) return error; } @@ -678,10 +680,11 @@ xfs_file_dio_aio_write( xfs_rw_ilock(ip, iolock); } - ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock); + ret = xfs_file_aio_write_checks(iocb, from, &iolock); if (ret) goto out; - iov_iter_truncate(from, count); + count = iov_iter_count(from); + pos = iocb->ki_pos; if (mapping->nrpages) { ret = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, @@ -734,24 +737,22 @@ xfs_file_buffered_aio_write( ssize_t ret; int enospc = 0; int iolock = XFS_IOLOCK_EXCL; - loff_t pos = iocb->ki_pos; - size_t count = iov_iter_count(from); xfs_rw_ilock(ip, iolock); - ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock); + ret = xfs_file_aio_write_checks(iocb, from, &iolock); if (ret) goto out; - iov_iter_truncate(from, count); /* We can write back this queue in page reclaim */ current->backing_dev_info = inode_to_bdi(inode); write_retry: - trace_xfs_file_buffered_write(ip, count, iocb->ki_pos, 0); - ret = generic_perform_write(file, from, pos); + trace_xfs_file_buffered_write(ip, iov_iter_count(from), + iocb->ki_pos, 0); + ret = generic_perform_write(file, from, iocb->ki_pos); if (likely(ret >= 0)) - iocb->ki_pos = pos + ret; + iocb->ki_pos += ret; /* * If we hit a space limit, try to free up some lingering preallocated @@ -803,7 +804,7 @@ xfs_file_write_iter( if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return -EIO; - if (unlikely(file->f_flags & O_DIRECT)) + if (unlikely(iocb->ki_flags & IOCB_DIRECT)) ret = xfs_file_dio_aio_write(iocb, from); else ret = xfs_file_buffered_aio_write(iocb, from); diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h index 0d4d3590cf85..996a04064894 100644 --- a/fs/xfs/xfs_qm.h +++ b/fs/xfs/xfs_qm.h @@ -168,10 +168,6 @@ extern int xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t, uint, struct qc_dqblk *); extern int xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint, struct qc_dqblk *); -extern int xfs_qm_scall_getqstat(struct xfs_mount *, - struct fs_quota_stat *); -extern int xfs_qm_scall_getqstatv(struct xfs_mount *, - struct fs_quota_statv *); extern int xfs_qm_scall_quotaon(struct xfs_mount *, uint); extern int xfs_qm_scall_quotaoff(struct xfs_mount *, uint); diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c index 9b965db45800..9a25c9275fb3 100644 --- a/fs/xfs/xfs_qm_syscalls.c +++ b/fs/xfs/xfs_qm_syscalls.c @@ -38,7 +38,6 @@ STATIC int xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint); STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *, uint); -STATIC uint xfs_qm_export_flags(uint); /* * Turn off quota accounting and/or enforcement for all udquots and/or @@ -389,159 +388,6 @@ xfs_qm_scall_quotaon( return 0; } - -/* - * Return quota status information, such as uquota-off, enforcements, etc. - * for Q_XGETQSTAT command. - */ -int -xfs_qm_scall_getqstat( - struct xfs_mount *mp, - struct fs_quota_stat *out) -{ - struct xfs_quotainfo *q = mp->m_quotainfo; - struct xfs_inode *uip = NULL; - struct xfs_inode *gip = NULL; - struct xfs_inode *pip = NULL; - bool tempuqip = false; - bool tempgqip = false; - bool temppqip = false; - - memset(out, 0, sizeof(fs_quota_stat_t)); - - out->qs_version = FS_QSTAT_VERSION; - out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags & - (XFS_ALL_QUOTA_ACCT| - XFS_ALL_QUOTA_ENFD)); - uip = q->qi_uquotaip; - gip = q->qi_gquotaip; - pip = q->qi_pquotaip; - if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, - 0, 0, &uip) == 0) - tempuqip = true; - } - if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, - 0, 0, &gip) == 0) - tempgqip = true; - } - /* - * Q_XGETQSTAT doesn't have room for both group and project quotas. - * So, allow the project quota values to be copied out only if - * there is no group quota information available. - */ - if (!gip) { - if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino, - 0, 0, &pip) == 0) - temppqip = true; - } - } else - pip = NULL; - if (uip) { - out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino; - out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks; - out->qs_uquota.qfs_nextents = uip->i_d.di_nextents; - if (tempuqip) - IRELE(uip); - } - - if (gip) { - out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; - out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks; - out->qs_gquota.qfs_nextents = gip->i_d.di_nextents; - if (tempgqip) - IRELE(gip); - } - if (pip) { - out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; - out->qs_gquota.qfs_nblks = pip->i_d.di_nblocks; - out->qs_gquota.qfs_nextents = pip->i_d.di_nextents; - if (temppqip) - IRELE(pip); - } - out->qs_incoredqs = q->qi_dquots; - out->qs_btimelimit = q->qi_btimelimit; - out->qs_itimelimit = q->qi_itimelimit; - out->qs_rtbtimelimit = q->qi_rtbtimelimit; - out->qs_bwarnlimit = q->qi_bwarnlimit; - out->qs_iwarnlimit = q->qi_iwarnlimit; - - return 0; -} - -/* - * Return quota status information, such as uquota-off, enforcements, etc. - * for Q_XGETQSTATV command, to support separate project quota field. - */ -int -xfs_qm_scall_getqstatv( - struct xfs_mount *mp, - struct fs_quota_statv *out) -{ - struct xfs_quotainfo *q = mp->m_quotainfo; - struct xfs_inode *uip = NULL; - struct xfs_inode *gip = NULL; - struct xfs_inode *pip = NULL; - bool tempuqip = false; - bool tempgqip = false; - bool temppqip = false; - - out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags & - (XFS_ALL_QUOTA_ACCT| - XFS_ALL_QUOTA_ENFD)); - out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino; - out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; - out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino; - - uip = q->qi_uquotaip; - gip = q->qi_gquotaip; - pip = q->qi_pquotaip; - if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, - 0, 0, &uip) == 0) - tempuqip = true; - } - if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, - 0, 0, &gip) == 0) - tempgqip = true; - } - if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino, - 0, 0, &pip) == 0) - temppqip = true; - } - if (uip) { - out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks; - out->qs_uquota.qfs_nextents = uip->i_d.di_nextents; - if (tempuqip) - IRELE(uip); - } - - if (gip) { - out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks; - out->qs_gquota.qfs_nextents = gip->i_d.di_nextents; - if (tempgqip) - IRELE(gip); - } - if (pip) { - out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks; - out->qs_pquota.qfs_nextents = pip->i_d.di_nextents; - if (temppqip) - IRELE(pip); - } - out->qs_incoredqs = q->qi_dquots; - out->qs_btimelimit = q->qi_btimelimit; - out->qs_itimelimit = q->qi_itimelimit; - out->qs_rtbtimelimit = q->qi_rtbtimelimit; - out->qs_bwarnlimit = q->qi_bwarnlimit; - out->qs_iwarnlimit = q->qi_iwarnlimit; - - return 0; -} - #define XFS_QC_MASK \ (QC_LIMIT_MASK | QC_TIMER_MASK | QC_WARNS_MASK) @@ -873,28 +719,6 @@ out_put: return error; } -STATIC uint -xfs_qm_export_flags( - uint flags) -{ - uint uflags; - - uflags = 0; - if (flags & XFS_UQUOTA_ACCT) - uflags |= FS_QUOTA_UDQ_ACCT; - if (flags & XFS_GQUOTA_ACCT) - uflags |= FS_QUOTA_GDQ_ACCT; - if (flags & XFS_PQUOTA_ACCT) - uflags |= FS_QUOTA_PDQ_ACCT; - if (flags & XFS_UQUOTA_ENFD) - uflags |= FS_QUOTA_UDQ_ENFD; - if (flags & XFS_GQUOTA_ENFD) - uflags |= FS_QUOTA_GDQ_ENFD; - if (flags & XFS_PQUOTA_ENFD) - uflags |= FS_QUOTA_PDQ_ENFD; - return uflags; -} - STATIC int xfs_dqrele_inode( diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c index 6923905ab33d..7795e0d01382 100644 --- a/fs/xfs/xfs_quotaops.c +++ b/fs/xfs/xfs_quotaops.c @@ -23,10 +23,81 @@ #include "xfs_inode.h" #include "xfs_quota.h" #include "xfs_trans.h" +#include "xfs_trace.h" +#include "xfs_icache.h" #include "xfs_qm.h" #include <linux/quota.h> +static void +xfs_qm_fill_state( + struct qc_type_state *tstate, + struct xfs_mount *mp, + struct xfs_inode *ip, + xfs_ino_t ino) +{ + struct xfs_quotainfo *q = mp->m_quotainfo; + bool tempqip = false; + + tstate->ino = ino; + if (!ip && ino == NULLFSINO) + return; + if (!ip) { + if (xfs_iget(mp, NULL, ino, 0, 0, &ip)) + return; + tempqip = true; + } + tstate->flags |= QCI_SYSFILE; + tstate->blocks = ip->i_d.di_nblocks; + tstate->nextents = ip->i_d.di_nextents; + tstate->spc_timelimit = q->qi_btimelimit; + tstate->ino_timelimit = q->qi_itimelimit; + tstate->rt_spc_timelimit = q->qi_rtbtimelimit; + tstate->spc_warnlimit = q->qi_bwarnlimit; + tstate->ino_warnlimit = q->qi_iwarnlimit; + tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit; + if (tempqip) + IRELE(ip); +} + +/* + * Return quota status information, such as enforcements, quota file inode + * numbers etc. + */ +static int +xfs_fs_get_quota_state( + struct super_block *sb, + struct qc_state *state) +{ + struct xfs_mount *mp = XFS_M(sb); + struct xfs_quotainfo *q = mp->m_quotainfo; + + memset(state, 0, sizeof(*state)); + if (!XFS_IS_QUOTA_RUNNING(mp)) + return 0; + state->s_incoredqs = q->qi_dquots; + if (XFS_IS_UQUOTA_RUNNING(mp)) + state->s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED; + if (XFS_IS_UQUOTA_ENFORCED(mp)) + state->s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED; + if (XFS_IS_GQUOTA_RUNNING(mp)) + state->s_state[GRPQUOTA].flags |= QCI_ACCT_ENABLED; + if (XFS_IS_GQUOTA_ENFORCED(mp)) + state->s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED; + if (XFS_IS_PQUOTA_RUNNING(mp)) + state->s_state[PRJQUOTA].flags |= QCI_ACCT_ENABLED; + if (XFS_IS_PQUOTA_ENFORCED(mp)) + state->s_state[PRJQUOTA].flags |= QCI_LIMITS_ENFORCED; + + xfs_qm_fill_state(&state->s_state[USRQUOTA], mp, q->qi_uquotaip, + mp->m_sb.sb_uquotino); + xfs_qm_fill_state(&state->s_state[GRPQUOTA], mp, q->qi_gquotaip, + mp->m_sb.sb_gquotino); + xfs_qm_fill_state(&state->s_state[PRJQUOTA], mp, q->qi_pquotaip, + mp->m_sb.sb_pquotino); + return 0; +} + STATIC int xfs_quota_type(int type) { @@ -40,28 +111,40 @@ xfs_quota_type(int type) } } -STATIC int -xfs_fs_get_xstate( +#define XFS_QC_SETINFO_MASK (QC_TIMER_MASK | QC_WARNS_MASK) + +/* + * Adjust quota timers & warnings + */ +static int +xfs_fs_set_info( struct super_block *sb, - struct fs_quota_stat *fqs) + int type, + struct qc_info *info) { - struct xfs_mount *mp = XFS_M(sb); + struct xfs_mount *mp = XFS_M(sb); + struct qc_dqblk newlim; + if (sb->s_flags & MS_RDONLY) + return -EROFS; if (!XFS_IS_QUOTA_RUNNING(mp)) return -ENOSYS; - return xfs_qm_scall_getqstat(mp, fqs); -} + if (!XFS_IS_QUOTA_ON(mp)) + return -ESRCH; + if (info->i_fieldmask & ~XFS_QC_SETINFO_MASK) + return -EINVAL; + if ((info->i_fieldmask & XFS_QC_SETINFO_MASK) == 0) + return 0; -STATIC int -xfs_fs_get_xstatev( - struct super_block *sb, - struct fs_quota_statv *fqs) -{ - struct xfs_mount *mp = XFS_M(sb); + newlim.d_fieldmask = info->i_fieldmask; + newlim.d_spc_timer = info->i_spc_timelimit; + newlim.d_ino_timer = info->i_ino_timelimit; + newlim.d_rt_spc_timer = info->i_rt_spc_timelimit; + newlim.d_ino_warns = info->i_ino_warnlimit; + newlim.d_spc_warns = info->i_spc_warnlimit; + newlim.d_rt_spc_warns = info->i_rt_spc_warnlimit; - if (!XFS_IS_QUOTA_RUNNING(mp)) - return -ENOSYS; - return xfs_qm_scall_getqstatv(mp, fqs); + return xfs_qm_scall_setqlim(mp, 0, xfs_quota_type(type), &newlim); } static unsigned int @@ -178,8 +261,8 @@ xfs_fs_set_dqblk( } const struct quotactl_ops xfs_quotactl_operations = { - .get_xstatev = xfs_fs_get_xstatev, - .get_xstate = xfs_fs_get_xstate, + .get_state = xfs_fs_get_quota_state, + .set_info = xfs_fs_set_info, .quota_enable = xfs_quota_enable, .quota_disable = xfs_quota_disable, .rm_xquota = xfs_fs_rm_xquota, |