[PATCH 4/7] fuse: introduce FUSE_I_CTIME_DIRTY flag

From: Maxim Patlasov
Date: Tue Apr 15 2014 - 07:30:55 EST


The flag plays the role similar to FUSE_I_MTIME_DIRTY: local ctime
(inode->i_ctime) is newer than on the server; so, local ctime must be
flushed to the server afterwards.

The patch only introduces the flag, extends API (fuse_setattr_in) properly,
and implements the flush procedure (fuse_flush_cmtime()). Further patches of
the patch-set will implement the logic of setting and clearing the flag.

Signed-off-by: Maxim Patlasov <MPatlasov@xxxxxxxxxxxxx>
---
fs/fuse/dir.c | 22 ++++++++++++++++++----
fs/fuse/file.c | 11 ++++-------
fs/fuse/fuse_i.h | 4 +++-
include/uapi/linux/fuse.h | 11 ++++++++---
4 files changed, 33 insertions(+), 15 deletions(-)

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index c7cb41c..0596726 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1600,9 +1600,9 @@ static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_req *req,
}

/*
- * Flush inode->i_mtime to the server
+ * Flush inode->i_mtime and inode->i_ctime to the server
*/
-int fuse_flush_mtime(struct file *file, bool nofail)
+int fuse_flush_cmtime(struct file *file, bool nofail)
{
struct inode *inode = file->f_mapping->host;
struct fuse_inode *fi = get_fuse_inode(inode);
@@ -1610,8 +1610,16 @@ int fuse_flush_mtime(struct file *file, bool nofail)
struct fuse_req *req = NULL;
struct fuse_setattr_in inarg;
struct fuse_attr_out outarg;
+ unsigned cmtime_flags = 0;
int err;

+ if (test_bit(FUSE_I_MTIME_DIRTY, &fi->state))
+ cmtime_flags |= FATTR_MTIME;
+ if (test_bit(FUSE_I_CTIME_DIRTY, &fi->state) && fc->minor >= 24)
+ cmtime_flags |= FATTR_CTIME;
+ if (!cmtime_flags)
+ return 0;
+
if (nofail) {
req = fuse_get_req_nofail_nopages(fc, file);
} else {
@@ -1623,17 +1631,23 @@ int fuse_flush_mtime(struct file *file, bool nofail)
memset(&inarg, 0, sizeof(inarg));
memset(&outarg, 0, sizeof(outarg));

- inarg.valid |= FATTR_MTIME;
+ inarg.valid = cmtime_flags;
inarg.mtime = inode->i_mtime.tv_sec;
inarg.mtimensec = inode->i_mtime.tv_nsec;
+ if (fc->minor >= 24) {
+ inarg.ctime = inode->i_ctime.tv_sec;
+ inarg.ctimensec = inode->i_ctime.tv_nsec;
+ }

fuse_setattr_fill(fc, req, inode, &inarg, &outarg);
fuse_request_send(fc, req);
err = req->out.h.error;
fuse_put_request(fc, req);

- if (!err)
+ if (!err) {
clear_bit(FUSE_I_MTIME_DIRTY, &fi->state);
+ clear_bit(FUSE_I_CTIME_DIRTY, &fi->state);
+ }

return err;
}
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index c2c6df7..9ed8590b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -328,8 +328,7 @@ static int fuse_release(struct inode *inode, struct file *file)
if (fc->writeback_cache)
filemap_write_and_wait(file->f_mapping);

- if (test_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state))
- fuse_flush_mtime(file, true);
+ fuse_flush_cmtime(file, true);

fuse_release_common(file, FUSE_RELEASE);

@@ -512,11 +511,9 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end,

fuse_sync_writes(inode);

- if (test_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state)) {
- int err = fuse_flush_mtime(file, false);
- if (err)
- goto out;
- }
+ err = fuse_flush_cmtime(file, false);
+ if (err)
+ goto out;

req = fuse_get_req_nopages(fc);
if (IS_ERR(req)) {
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index a257ed8e..781a01d 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -121,6 +121,8 @@ enum {
FUSE_I_SIZE_UNSTABLE,
/** i_mtime has been updated locally; a flush to userspace needed */
FUSE_I_MTIME_DIRTY,
+ /** i_ctime has been updated locally; a flush to userspace needed */
+ FUSE_I_CTIME_DIRTY,
};

struct fuse_conn;
@@ -891,7 +893,7 @@ int fuse_dev_release(struct inode *inode, struct file *file);

bool fuse_write_update_size(struct inode *inode, loff_t pos);

-int fuse_flush_mtime(struct file *file, bool nofail);
+int fuse_flush_cmtime(struct file *file, bool nofail);

int fuse_do_setattr(struct inode *inode, struct iattr *attr,
struct file *file);
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index cf4750e..8af06cc 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -96,6 +96,10 @@
*
* 7.23
* - add FUSE_WRITEBACK_CACHE
+ *
+ * 7.24
+ * - ctime support for FUSE_WRITEBACK_CACHE:
+ * changes in fuse_setattr_in and fuse_forget_in
*/

#ifndef _LINUX_FUSE_H
@@ -131,7 +135,7 @@
#define FUSE_KERNEL_VERSION 7

/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 23
+#define FUSE_KERNEL_MINOR_VERSION 24

/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -191,6 +195,7 @@ struct fuse_file_lock {
#define FATTR_ATIME_NOW (1 << 7)
#define FATTR_MTIME_NOW (1 << 8)
#define FATTR_LOCKOWNER (1 << 9)
+#define FATTR_CTIME (1 << 10)

/**
* Flags returned by the OPEN request
@@ -438,10 +443,10 @@ struct fuse_setattr_in {
uint64_t lock_owner;
uint64_t atime;
uint64_t mtime;
- uint64_t unused2;
+ uint64_t ctime;
uint32_t atimensec;
uint32_t mtimensec;
- uint32_t unused3;
+ uint32_t ctimensec;
uint32_t mode;
uint32_t unused4;
uint32_t uid;

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/