From patchwork Sat Mar 10 18:18:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andiry Xu X-Patchwork-Id: 10273947 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 9F740602BD for ; Sat, 10 Mar 2018 18:21:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8DBA128BAE for ; Sat, 10 Mar 2018 18:21:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8299E296E5; Sat, 10 Mar 2018 18:21:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=no version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id EF5A028BAE for ; Sat, 10 Mar 2018 18:21:37 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id CF6CD226462EF; Sat, 10 Mar 2018 10:15:09 -0800 (PST) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2607:f8b0:400e:c01::241; helo=mail-pl0-x241.google.com; envelope-from=jix024@eng.ucsd.edu; receiver=linux-nvdimm@lists.01.org Received: from mail-pl0-x241.google.com (mail-pl0-x241.google.com [IPv6:2607:f8b0:400e:c01::241]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id E46DD226462E5 for ; Sat, 10 Mar 2018 10:15:08 -0800 (PST) Received: by mail-pl0-x241.google.com with SMTP id f23-v6so7024355plr.10 for ; Sat, 10 Mar 2018 10:21:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=eng.ucsd.edu; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=96X+TML9KG+DSGWh6PMN69WotJlGpbbOE0ybVlJfClA=; b=btaOJ7RCo4qB3MuqZg8rL3uU0ZBpXZSz5JFqdIaaWqX77z6RC9605kiDmRBRGqM6ME rV9IIhgAuk30K7+VSiAZUbr7lnoXAhRfjYk5D7dmZH7KwKFS/DeXmZrdJ300tl/R17va Ftc7UlZ/3OfmjUFA3cl3D2F03XYyueOWE7PBY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=96X+TML9KG+DSGWh6PMN69WotJlGpbbOE0ybVlJfClA=; b=gTU73lIw2jt0kcpd/SX5WXetrEN6m/gxCQyC4EXilk3N+XW90p7tH7p0+M0g0UAAT7 ag1HVX2SdfAGD6UzCsJP+EYVtbIsB5B7TxPXcNfFsxAxTSmTCIDyQJZsgq+esyy/Fmkq 6vjfIvwYcvEJZyyx+vREKPqXLloVi+Vejr5fMgGRu8mffmH8TZEPgeWvsUQzc+v7ufwK S9Mcip8HpDHjMMe9MzEAaNlg8zc8KqaK4PY+9nv0bnzPlyVxHIw/Kux1dBbo0Xizj40g just5USlgSomzVZU+3IV/5z5+ZIIBxozsIXlJ8jdtRSqiGRxbsPOb6rVq0TZSnxjSfO+ mpag== X-Gm-Message-State: AElRT7HkkEIysatnQRqTMK4hQEb+ADvBiTK9S93vCY0eworfEjR+r+8j DkS1Bos6jH26xPdsDVL8gXtKaQ== X-Google-Smtp-Source: AG47ELv3RPKYixRolLe4NaFcEm1vlgDbXUT19U/MMY9Um/5jk5D5mBoLgzYYLxlGvrGGuoWHZXpBhA== X-Received: by 2002:a17:902:bd46:: with SMTP id b6-v6mr2689563plx.247.1520706087317; Sat, 10 Mar 2018 10:21:27 -0800 (PST) Received: from brienza-desktop.8.8.4.4 (andxu.ucsd.edu. [132.239.17.134]) by smtp.gmail.com with ESMTPSA id h80sm9210167pfj.181.2018.03.10.10.21.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 10 Mar 2018 10:21:26 -0800 (PST) From: Andiry Xu To: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-nvdimm@lists.01.org Subject: [RFC v2 59/83] Namei: setattr Date: Sat, 10 Mar 2018 10:18:40 -0800 Message-Id: <1520705944-6723-60-git-send-email-jix024@eng.ucsd.edu> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1520705944-6723-1-git-send-email-jix024@eng.ucsd.edu> References: <1520705944-6723-1-git-send-email-jix024@eng.ucsd.edu> X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: coughlan@redhat.com, miklos@szeredi.hu, Andiry Xu , david@fromorbit.com, jack@suse.com, swanson@cs.ucsd.edu, swhiteho@redhat.com, andiry.xu@gmail.com MIME-Version: 1.0 Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP From: Andiry Xu Add notify_change for setattr operations. Truncate the file blocks if the file is shrunk. Signed-off-by: Andiry Xu --- fs/nova/inode.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/nova/inode.h | 1 + fs/nova/namei.c | 2 + 3 files changed, 183 insertions(+) diff --git a/fs/nova/inode.c b/fs/nova/inode.c index 2d3f7a3..2092a55 100644 --- a/fs/nova/inode.c +++ b/fs/nova/inode.c @@ -141,6 +141,58 @@ void nova_set_inode_flags(struct inode *inode, struct nova_inode *pi, inode->i_flags |= S_DAX; } +static inline void check_eof_blocks(struct super_block *sb, + struct nova_inode *pi, struct inode *inode, + struct nova_inode_info_header *sih) +{ + if ((pi->i_flags & cpu_to_le32(NOVA_EOFBLOCKS_FL)) && + (inode->i_size + sb->s_blocksize) > (sih->i_blocks + << sb->s_blocksize_bits)) { + pi->i_flags &= cpu_to_le32(~NOVA_EOFBLOCKS_FL); + nova_persist_inode(pi); + } +} + +/* + * Free data blocks from inode in the range start <=> end + */ +static void nova_truncate_file_blocks(struct inode *inode, loff_t start, + loff_t end, u64 epoch_id) +{ + struct super_block *sb = inode->i_sb; + struct nova_inode *pi = nova_get_inode(sb, inode); + struct nova_inode_info *si = NOVA_I(inode); + struct nova_inode_info_header *sih = &si->header; + unsigned int data_bits = blk_type_to_shift[sih->i_blk_type]; + unsigned long first_blocknr, last_blocknr; + int freed = 0; + + inode->i_mtime = inode->i_ctime = current_time(inode); + + nova_dbg_verbose("truncate: pi %p iblocks %lx %llx %llx %llx\n", pi, + sih->i_blocks, start, end, pi->i_size); + + first_blocknr = (start + (1UL << data_bits) - 1) >> data_bits; + + if (end == 0) + return; + last_blocknr = (end - 1) >> data_bits; + + if (first_blocknr > last_blocknr) + return; + + freed = nova_delete_file_tree(sb, sih, first_blocknr, + last_blocknr, true, false, epoch_id); + + inode->i_blocks -= (freed * (1 << (data_bits - + sb->s_blocksize_bits))); + + sih->i_blocks = inode->i_blocks; + /* Check for the flag EOFBLOCKS is still valid after the set size */ + check_eof_blocks(sb, pi, inode, sih); + +} + /* copy persistent state to struct inode */ static int nova_read_inode(struct super_block *sb, struct inode *inode, u64 pi_addr) @@ -963,6 +1015,134 @@ void nova_dirty_inode(struct inode *inode, int flags) nova_flush_buffer(&pi->i_atime, sizeof(pi->i_atime), 0); } +/* + * Zero the tail page. Used in resize request + * to avoid to keep data in case the file grows again. + */ +static void nova_clear_last_page_tail(struct super_block *sb, + struct inode *inode, loff_t newsize) +{ + struct nova_sb_info *sbi = NOVA_SB(sb); + struct nova_inode_info *si = NOVA_I(inode); + struct nova_inode_info_header *sih = &si->header; + unsigned long offset = newsize & (sb->s_blocksize - 1); + unsigned long pgoff, length; + u64 nvmm; + char *nvmm_addr; + + if (offset == 0 || newsize > inode->i_size) + return; + + length = sb->s_blocksize - offset; + pgoff = newsize >> sb->s_blocksize_bits; + + nvmm = nova_find_nvmm_block(sb, sih, NULL, pgoff); + if (nvmm == 0) + return; + + nvmm_addr = (char *)nova_get_block(sb, nvmm); + memcpy_to_pmem_nocache(nvmm_addr + offset, sbi->zeroed_page, length); +} + +static void nova_setsize(struct inode *inode, loff_t oldsize, loff_t newsize, + u64 epoch_id) +{ + struct super_block *sb = inode->i_sb; + struct nova_inode_info *si = NOVA_I(inode); + struct nova_inode_info_header *sih = &si->header; + timing_t setsize_time; + + /* We only support truncate regular file */ + if (!(S_ISREG(inode->i_mode))) { + nova_err(inode->i_sb, "%s:wrong file mode %x\n", inode->i_mode); + return; + } + + NOVA_START_TIMING(setsize_t, setsize_time); + + inode_dio_wait(inode); + + nova_dbgv("%s: inode %lu, old size %llu, new size %llu\n", + __func__, inode->i_ino, oldsize, newsize); + + sih_lock(sih); + if (newsize != oldsize) { + nova_clear_last_page_tail(sb, inode, newsize); + i_size_write(inode, newsize); + sih->i_size = newsize; + } + + /* FIXME: we should make sure that there is nobody reading the inode + * before truncating it. Also we need to munmap the truncated range + * from application address space, if mmapped. + */ + /* synchronize_rcu(); */ + + /* FIXME: Do we need to clear truncated DAX pages? */ +// dax_truncate_page(inode, newsize, nova_dax_get_block); + + truncate_pagecache(inode, newsize); + nova_truncate_file_blocks(inode, newsize, oldsize, epoch_id); + sih_unlock(sih); + NOVA_END_TIMING(setsize_t, setsize_time); +} + +int nova_notify_change(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + struct nova_inode_info *si = NOVA_I(inode); + struct nova_inode_info_header *sih = &si->header; + struct super_block *sb = inode->i_sb; + struct nova_inode *pi = nova_get_inode(sb, inode); + int ret; + unsigned int ia_valid = attr->ia_valid, attr_mask; + loff_t oldsize = inode->i_size; + u64 epoch_id; + timing_t setattr_time; + + NOVA_START_TIMING(setattr_t, setattr_time); + if (!pi) { + ret = -EACCES; + goto out; + } + + ret = setattr_prepare(dentry, attr); + if (ret) + goto out; + + /* Update inode with attr except for size */ + setattr_copy(inode, attr); + + epoch_id = nova_get_epoch_id(sb); + + attr_mask = ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_SIZE | ATTR_ATIME + | ATTR_MTIME | ATTR_CTIME; + + ia_valid = ia_valid & attr_mask; + + if (ia_valid == 0) + goto out; + + ret = nova_handle_setattr_operation(sb, inode, pi, ia_valid, + attr, epoch_id); + if (ret) + goto out; + + /* Only after log entry is committed, we can truncate size */ + if ((ia_valid & ATTR_SIZE) && (attr->ia_size != oldsize || + pi->i_flags & cpu_to_le32(NOVA_EOFBLOCKS_FL))) { +// nova_set_blocksize_hint(sb, inode, pi, attr->ia_size); + + /* now we can freely truncate the inode */ + nova_setsize(inode, oldsize, attr->ia_size, epoch_id); + } + + sih->trans_id++; +out: + NOVA_END_TIMING(setattr_t, setattr_time); + return ret; +} + static ssize_t nova_direct_IO(struct kiocb *iocb, struct iov_iter *iter) { /* DAX does not support direct IO */ diff --git a/fs/nova/inode.h b/fs/nova/inode.h index 42690e6..4ddf8c2 100644 --- a/fs/nova/inode.h +++ b/fs/nova/inode.h @@ -267,5 +267,6 @@ int nova_delete_file_tree(struct super_block *sb, extern void nova_evict_inode(struct inode *inode); extern int nova_write_inode(struct inode *inode, struct writeback_control *wbc); extern void nova_dirty_inode(struct inode *inode, int flags); +extern int nova_notify_change(struct dentry *dentry, struct iattr *attr); #endif diff --git a/fs/nova/namei.c b/fs/nova/namei.c index bb50c0a..1966bff 100644 --- a/fs/nova/namei.c +++ b/fs/nova/namei.c @@ -768,4 +768,6 @@ const struct inode_operations nova_dir_inode_operations = { .rmdir = nova_rmdir, .mknod = nova_mknod, .rename = nova_rename, + .setattr = nova_notify_change, + .get_acl = NULL, };