Received: by 10.223.185.111 with SMTP id b44csp1646990wrg; Sat, 10 Mar 2018 10:31:23 -0800 (PST) X-Google-Smtp-Source: AG47ELtByGYlA9dnHGBeEuatY7vkrD5Yoi4KPtKW9bvh7UL0Y1+7/+bI6IyYVSJenZ873MO1/dQA X-Received: by 10.98.204.69 with SMTP id a66mr2689306pfg.33.1520706683558; Sat, 10 Mar 2018 10:31:23 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1520706683; cv=none; d=google.com; s=arc-20160816; b=jUPiBfThqRln1h1GexhNAhVE9GOEAj+yBcH8MFVunIi0sPBpYmvOgtuNM0rwbDbuVX zDgss9zzkZ+mU3eLU4RdNe5isWvp4lguyTA7ZxNK00ts8nYOaTkANeBwyO92v8h9+HGV rbh0tQWLhjbei0HdW0w2h+IByD/jp1BTFLXaBB8tHFaxnlI0kXoGa+WDTLj55ewQJdMd SNZO7zbNw4kb1VhUQaItRUXRSR1QR7PuZlkR7xKLZVqDbG93C1BB+9uFPaWgZDY7U9vB rE9NaHQ1Ew+i6941GICnaHmgbD/cJEqHFEPkWYP2kMMCdvoxcJYHB69Sx//Bf/iWAddW FbhA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=96X+TML9KG+DSGWh6PMN69WotJlGpbbOE0ybVlJfClA=; b=FY0138Raz2pMmbDEvZZPqO54Z676xTSMJFlhEectr28C4Cwzk09UxQCG/S0HR+C4T8 CAcXG+mbRWD9bfLftQoIdNpRvZL5FUDO7IspTC28/mPsczM4l8eDn/I57iOTgi5dRmXB pEulcFgSTElxbxKK9+87BSLtMqHkeHrKBD5Z8Qpc2NbmN2tTv7ljMoWMgpdBNw33gEZX UltkzWQzGtWV9PDTVgSvVNv6ZwVjE6R2kbpz+G3Mn2VxDVMaW4cZ46e7EusY8xXAEW9d n3WqqCKdY6mTXKrJZwuGaZCPpX7bkahoGTy+mMD+58HMBvrxbh3Z3/+XAtaPKMXNokpV 3Vrw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@eng.ucsd.edu header.s=google header.b=btaOJ7RC; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m16si2645825pgn.290.2018.03.10.10.31.09; Sat, 10 Mar 2018 10:31:23 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@eng.ucsd.edu header.s=google header.b=btaOJ7RC; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752018AbeCJSaK (ORCPT + 99 others); Sat, 10 Mar 2018 13:30:10 -0500 Received: from mail-pl0-f65.google.com ([209.85.160.65]:32966 "EHLO mail-pl0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932720AbeCJSV2 (ORCPT ); Sat, 10 Mar 2018 13:21:28 -0500 Received: by mail-pl0-f65.google.com with SMTP id c11-v6so7036267plo.0 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=F27C9Y4rSg7IzRYRJZdHVeo5/2XtQhOTG4L1KCWJp244opmfLMsu0w8nPRrETwkpli 1DRwbauqPJGtGUgsCX0f+djtPIscXYnAzyHnCwPjrH9vtCSzy6osAimgL9VvqApUKBUD /r9763vJXMqpiuVVXtTONkcDFu1ZfsrcOWByb+LP6qqNLunvfnfT1TrIokldnmpyapXS 8XcHSTtRZKFterwBo12dcI+awRZjuMNAbMUqGbrS/GqvMcrk9QycWNRL8A2OzExa3Obu PX10FwgFOkAmgJST7VBEkcaaL0nFNAIdSKl6e3+5ieBF9PzbxkAyqwC0gZ3r/7Ocrfxo N9xw== X-Gm-Message-State: AElRT7GJ2lueBQMS3CZB7Yv3+sRfxDGr8M6Y69DQbpKU0XnCh5912kno AljvofW48b8PdMJTEl4WccSIlw== 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 Cc: dan.j.williams@intel.com, andy.rudoff@intel.com, coughlan@redhat.com, swanson@cs.ucsd.edu, david@fromorbit.com, jack@suse.com, swhiteho@redhat.com, miklos@szeredi.hu, andiry.xu@gmail.com, Andiry Xu 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> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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, }; -- 2.7.4