Merge tag 'v5.18'
authorKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
Tue, 31 May 2022 13:13:23 +0000 (16:13 +0300)
committerKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
Tue, 31 May 2022 13:13:23 +0000 (16:13 +0300)
Linux 5.18

fs/ntfs3/file.c
fs/ntfs3/frecord.c
fs/ntfs3/fslog.c
fs/ntfs3/inode.c
fs/ntfs3/xattr.c

index 787b53b984ee17ae07aff29f2972319d437387b7..3bae76930e68a012a00df9f35cc15cc3b35be1d6 100644 (file)
@@ -495,7 +495,7 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size)
 
        down_write(&ni->file.run_lock);
        err = attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run, new_size,
-                           &new_valid, true, NULL);
+                           &new_valid, ni->mi.sbi->options->prealloc, NULL);
        up_write(&ni->file.run_lock);
 
        if (new_valid < ni->i_valid)
@@ -662,7 +662,13 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
                /*
                 * Normal file: Allocate clusters, do not change 'valid' size.
                 */
-               err = ntfs_set_size(inode, max(end, i_size));
+               loff_t new_size = max(end, i_size);
+
+               err = inode_newsize_ok(inode, new_size);
+               if (err)
+                       goto out;
+
+               err = ntfs_set_size(inode, new_size);
                if (err)
                        goto out;
 
@@ -762,7 +768,7 @@ int ntfs3_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                }
                inode_dio_wait(inode);
 
-               if (attr->ia_size < oldsize)
+               if (attr->ia_size <= oldsize)
                        err = ntfs_truncate(inode, attr->ia_size);
                else if (attr->ia_size > oldsize)
                        err = ntfs_extend(inode, attr->ia_size, 0, NULL);
index 6f47a9c17f896c62e355db7a6948075a88247378..18842998c8fa3bdfc370fd01da437774e8fd6414 100644 (file)
@@ -1964,10 +1964,8 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
 
                vcn += clen;
 
-               if (vbo + bytes >= end) {
+               if (vbo + bytes >= end)
                        bytes = end - vbo;
-                       flags |= FIEMAP_EXTENT_LAST;
-               }
 
                if (vbo + bytes <= valid) {
                        ;
@@ -1977,6 +1975,9 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
                        /* vbo < valid && valid < vbo + bytes */
                        u64 dlen = valid - vbo;
 
+                       if (vbo + dlen >= end)
+                               flags |= FIEMAP_EXTENT_LAST;
+
                        err = fiemap_fill_next_extent(fieinfo, vbo, lbo, dlen,
                                                      flags);
                        if (err < 0)
@@ -1995,6 +1996,9 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
                        flags |= FIEMAP_EXTENT_UNWRITTEN;
                }
 
+               if (vbo + bytes >= end)
+                       flags |= FIEMAP_EXTENT_LAST;
+
                err = fiemap_fill_next_extent(fieinfo, vbo, lbo, bytes, flags);
                if (err < 0)
                        break;
index 06492f088d6020592bd4fdb8b1a6ecd22b823324..915f42cf07bcf85deee4a0ab7b74a985d18a9328 100644 (file)
@@ -4085,8 +4085,10 @@ process_log:
                if (client == LFS_NO_CLIENT_LE) {
                        /* Insert "NTFS" client LogFile. */
                        client = ra->client_idx[0];
-                       if (client == LFS_NO_CLIENT_LE)
-                               return -EINVAL;
+                       if (client == LFS_NO_CLIENT_LE) {
+                               err = -EINVAL;
+                               goto out;
+                       }
 
                        t16 = le16_to_cpu(client);
                        cr = ca + t16;
index 9eab11e3b03415528f9b7beedcea58a747c43553..76519c72a970fcbf1c8cebef56d4e81975d5c6c0 100644 (file)
@@ -757,6 +757,7 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        loff_t vbo = iocb->ki_pos;
        loff_t end;
        int wr = iov_iter_rw(iter) & WRITE;
+       size_t iter_count = iov_iter_count(iter);
        loff_t valid;
        ssize_t ret;
 
@@ -770,10 +771,13 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
                                 wr ? ntfs_get_block_direct_IO_W
                                    : ntfs_get_block_direct_IO_R);
 
-       if (ret <= 0)
+       if (ret > 0)
+               end = vbo + ret;
+       else if (wr && ret == -EIOCBQUEUED)
+               end = vbo + iter_count;
+       else
                goto out;
 
-       end = vbo + ret;
        valid = ni->i_valid;
        if (wr) {
                if (end > valid && !S_ISBLK(inode->i_mode)) {
index afd0ddad826ff49f661ce758bcbecec46921fd1c..5e0e0280e70debaac0c9e9478a65853b7deb8c1b 100644 (file)
@@ -112,7 +112,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
                return -ENOMEM;
 
        if (!size) {
-               ;
+               /* EA info persists, but xattr is empty. Looks like EA problem. */
        } else if (attr_ea->non_res) {
                struct runs_tree run;
 
@@ -259,7 +259,7 @@ out:
 
 static noinline int ntfs_set_ea(struct inode *inode, const char *name,
                                size_t name_len, const void *value,
-                               size_t val_size, int flags)
+                               size_t val_size, int flags, bool locked)
 {
        struct ntfs_inode *ni = ntfs_i(inode);
        struct ntfs_sb_info *sbi = ni->mi.sbi;
@@ -278,7 +278,8 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
        u64 new_sz;
        void *p;
 
-       ni_lock(ni);
+       if (!locked)
+               ni_lock(ni);
 
        run_init(&ea_run);
 
@@ -467,7 +468,8 @@ update_ea:
        mark_inode_dirty(&ni->vfs_inode);
 
 out:
-       ni_unlock(ni);
+       if (!locked)
+               ni_unlock(ni);
 
        run_close(&ea_run);
        kfree(ea_all);
@@ -541,7 +543,7 @@ struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu)
 
 static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
                                    struct inode *inode, struct posix_acl *acl,
-                                   int type)
+                                   int type, bool init_acl)
 {
        const char *name;
        size_t size, name_len;
@@ -554,8 +556,9 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               if (acl) {
-                       umode_t mode = inode->i_mode;
+               /* Do not change i_mode if we are in init_acl */
+               if (acl && !init_acl) {
+                       umode_t mode;
 
                        err = posix_acl_update_mode(mnt_userns, inode, &mode,
                                                    &acl);
@@ -598,7 +601,7 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
                flags = 0;
        }
 
-       err = ntfs_set_ea(inode, name, name_len, value, size, flags);
+       err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);
        if (err == -ENODATA && !size)
                err = 0; /* Removing non existed xattr. */
        if (!err)
@@ -616,7 +619,68 @@ out:
 int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
                 struct posix_acl *acl, int type)
 {
-       return ntfs_set_acl_ex(mnt_userns, inode, acl, type);
+       return ntfs_set_acl_ex(mnt_userns, inode, acl, type, false);
+}
+
+static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
+                             struct inode *inode, int type, void *buffer,
+                             size_t size)
+{
+       struct posix_acl *acl;
+       int err;
+
+       if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
+               ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
+               return -EOPNOTSUPP;
+       }
+
+       acl = ntfs_get_acl(inode, type, false);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+
+       if (!acl)
+               return -ENODATA;
+
+       err = posix_acl_to_xattr(mnt_userns, acl, buffer, size);
+       posix_acl_release(acl);
+
+       return err;
+}
+
+static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
+                             struct inode *inode, int type, const void *value,
+                             size_t size)
+{
+       struct posix_acl *acl;
+       int err;
+
+       if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
+               ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
+               return -EOPNOTSUPP;
+       }
+
+       if (!inode_owner_or_capable(mnt_userns, inode))
+               return -EPERM;
+
+       if (!value) {
+               acl = NULL;
+       } else {
+               acl = posix_acl_from_xattr(mnt_userns, value, size);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+
+               if (acl) {
+                       err = posix_acl_valid(mnt_userns, acl);
+                       if (err)
+                               goto release_and_out;
+               }
+       }
+
+       err = ntfs_set_acl(mnt_userns, inode, acl, type);
+
+release_and_out:
+       posix_acl_release(acl);
+       return err;
 }
 
 /*
@@ -636,7 +700,7 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
 
        if (default_acl) {
                err = ntfs_set_acl_ex(mnt_userns, inode, default_acl,
-                                     ACL_TYPE_DEFAULT);
+                                     ACL_TYPE_DEFAULT, true);
                posix_acl_release(default_acl);
        } else {
                inode->i_default_acl = NULL;
@@ -647,7 +711,7 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
        else {
                if (!err)
                        err = ntfs_set_acl_ex(mnt_userns, inode, acl,
-                                             ACL_TYPE_ACCESS);
+                                             ACL_TYPE_ACCESS, true);
                posix_acl_release(acl);
        }
 
@@ -785,6 +849,23 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
                goto out;
        }
 
+#ifdef CONFIG_NTFS3_FS_POSIX_ACL
+       if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
+            !memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
+                    sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
+           (name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
+            !memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
+                    sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
+               /* TODO: init_user_ns? */
+               err = ntfs_xattr_get_acl(
+                       &init_user_ns, inode,
+                       name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
+                               ? ACL_TYPE_ACCESS
+                               : ACL_TYPE_DEFAULT,
+                       buffer, size);
+               goto out;
+       }
+#endif
        /* Deal with NTFS extended attribute. */
        err = ntfs_get_ea(inode, name, name_len, buffer, size, NULL);
 
@@ -897,10 +978,29 @@ set_new_fa:
                goto out;
        }
 
+#ifdef CONFIG_NTFS3_FS_POSIX_ACL
+       if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
+            !memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
+                    sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
+           (name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
+            !memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
+                    sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
+               err = ntfs_xattr_set_acl(
+                       mnt_userns, inode,
+                       name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
+                               ? ACL_TYPE_ACCESS
+                               : ACL_TYPE_DEFAULT,
+                       value, size);
+               goto out;
+       }
+#endif
        /* Deal with NTFS extended attribute. */
-       err = ntfs_set_ea(inode, name, name_len, value, size, flags);
+       err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);
 
 out:
+       inode->i_ctime = current_time(inode);
+       mark_inode_dirty(inode);
+
        return err;
 }
 
@@ -913,35 +1013,37 @@ int ntfs_save_wsl_perm(struct inode *inode)
 {
        int err;
        __le32 value;
+       struct ntfs_inode *ni = ntfs_i(inode);
 
-       /* TODO: refactor this, so we don't lock 4 times in ntfs_set_ea */
+       ni_lock(ni);
        value = cpu_to_le32(i_uid_read(inode));
        err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value,
-                         sizeof(value), 0);
+                         sizeof(value), 0, true); /* true == already locked. */
        if (err)
                goto out;
 
        value = cpu_to_le32(i_gid_read(inode));
        err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value,
-                         sizeof(value), 0);
+                         sizeof(value), 0, true);
        if (err)
                goto out;
 
        value = cpu_to_le32(inode->i_mode);
        err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value,
-                         sizeof(value), 0);
+                         sizeof(value), 0, true);
        if (err)
                goto out;
 
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
                value = cpu_to_le32(inode->i_rdev);
                err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value,
-                                 sizeof(value), 0);
+                                 sizeof(value), 0, true);
                if (err)
                        goto out;
        }
 
 out:
+       ni_unlock(ni);
        /* In case of error should we delete all WSL xattr? */
        return err;
 }