Skip to content

Commit 972f4c4

Browse files
author
Miklos Szeredi
committed
fuse: cache btime
Not all inode attributes are supported by all filesystems, but for the basic stats (which are returned by stat(2) and friends) all of them will have some value, even if that doesn't reflect a real attribute of the file. Btime is different, in that filesystems are free to report or not report a value in statx. If the value is available, then STATX_BTIME bit is set in stx_mask. When caching the value of btime, remember the availability of the attribute as well as the value (if available). This is done by using the FUSE_I_BTIME bit in fuse_inode->state to indicate availability, while using fuse_inode->inval_mask & STATX_BTIME to indicate the state of the cache itself (i.e. set if cache is invalid, and cleared if cache is valid). Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
1 parent d304553 commit 972f4c4

File tree

4 files changed

+40
-8
lines changed

4 files changed

+40
-8
lines changed

fs/fuse/dir.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
255255
goto invalid;
256256

257257
forget_all_cached_acls(inode);
258-
fuse_change_attributes(inode, &outarg.attr,
258+
fuse_change_attributes(inode, &outarg.attr, NULL,
259259
ATTR_TIMEOUT(&outarg),
260260
attr_version);
261261
fuse_change_entry_timeout(entry, &outarg);
@@ -1213,8 +1213,8 @@ static int fuse_do_statx(struct inode *inode, struct file *file,
12131213

12141214
fuse_statx_to_attr(&outarg.stat, &attr);
12151215
if ((sx->mask & STATX_BASIC_STATS) == STATX_BASIC_STATS) {
1216-
fuse_change_attributes(inode, &attr, ATTR_TIMEOUT(&outarg),
1217-
attr_version);
1216+
fuse_change_attributes(inode, &attr, &outarg.stat,
1217+
ATTR_TIMEOUT(&outarg), attr_version);
12181218
}
12191219
stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME);
12201220
stat->btime.tv_sec = sx->btime.tv_sec;
@@ -1261,7 +1261,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
12611261
fuse_make_bad(inode);
12621262
err = -EIO;
12631263
} else {
1264-
fuse_change_attributes(inode, &outarg.attr,
1264+
fuse_change_attributes(inode, &outarg.attr, NULL,
12651265
ATTR_TIMEOUT(&outarg),
12661266
attr_version);
12671267
if (stat)
@@ -1316,6 +1316,10 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
13161316
generic_fillattr(&nop_mnt_idmap, inode, stat);
13171317
stat->mode = fi->orig_i_mode;
13181318
stat->ino = fi->orig_ino;
1319+
if (test_bit(FUSE_I_BTIME, &fi->state)) {
1320+
stat->btime = fi->i_btime;
1321+
stat->result_mask |= STATX_BTIME;
1322+
}
13191323
}
13201324

13211325
return err;
@@ -1952,7 +1956,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
19521956
/* FIXME: clear I_DIRTY_SYNC? */
19531957
}
19541958

1955-
fuse_change_attributes_common(inode, &outarg.attr,
1959+
fuse_change_attributes_common(inode, &outarg.attr, NULL,
19561960
ATTR_TIMEOUT(&outarg),
19571961
fuse_get_cache_mask(inode));
19581962
oldsize = inode->i_size;

fs/fuse/fuse_i.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ struct fuse_inode {
8888
preserve the original mode */
8989
umode_t orig_i_mode;
9090

91+
/* Cache birthtime */
92+
struct timespec64 i_btime;
93+
9194
/** 64 bit inode number */
9295
u64 orig_ino;
9396

@@ -167,6 +170,8 @@ enum {
167170
FUSE_I_SIZE_UNSTABLE,
168171
/* Bad inode */
169172
FUSE_I_BAD,
173+
/* Has btime */
174+
FUSE_I_BTIME,
170175
};
171176

172177
struct fuse_conn;
@@ -1064,9 +1069,11 @@ void fuse_init_symlink(struct inode *inode);
10641069
* Change attributes of an inode
10651070
*/
10661071
void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
1072+
struct fuse_statx *sx,
10671073
u64 attr_valid, u64 attr_version);
10681074

10691075
void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
1076+
struct fuse_statx *sx,
10701077
u64 attr_valid, u32 cache_mask);
10711078

10721079
u32 fuse_get_cache_mask(struct inode *inode);

fs/fuse/inode.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ static ino_t fuse_squash_ino(u64 ino64)
163163
}
164164

165165
void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
166+
struct fuse_statx *sx,
166167
u64 attr_valid, u32 cache_mask)
167168
{
168169
struct fuse_conn *fc = get_fuse_conn(inode);
@@ -198,6 +199,25 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
198199
inode->i_ctime.tv_sec = attr->ctime;
199200
inode->i_ctime.tv_nsec = attr->ctimensec;
200201
}
202+
if (sx) {
203+
/* Sanitize nsecs */
204+
sx->btime.tv_nsec =
205+
min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1);
206+
207+
/*
208+
* Btime has been queried, cache is valid (whether or not btime
209+
* is available or not) so clear STATX_BTIME from inval_mask.
210+
*
211+
* Availability of the btime attribute is indicated in
212+
* FUSE_I_BTIME
213+
*/
214+
set_mask_bits(&fi->inval_mask, STATX_BTIME, 0);
215+
if (sx->mask & STATX_BTIME) {
216+
set_bit(FUSE_I_BTIME, &fi->state);
217+
fi->i_btime.tv_sec = sx->btime.tv_sec;
218+
fi->i_btime.tv_nsec = sx->btime.tv_nsec;
219+
}
220+
}
201221

202222
if (attr->blksize != 0)
203223
inode->i_blkbits = ilog2(attr->blksize);
@@ -237,6 +257,7 @@ u32 fuse_get_cache_mask(struct inode *inode)
237257
}
238258

239259
void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
260+
struct fuse_statx *sx,
240261
u64 attr_valid, u64 attr_version)
241262
{
242263
struct fuse_conn *fc = get_fuse_conn(inode);
@@ -271,7 +292,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
271292
}
272293

273294
old_mtime = inode->i_mtime;
274-
fuse_change_attributes_common(inode, attr, attr_valid, cache_mask);
295+
fuse_change_attributes_common(inode, attr, sx, attr_valid, cache_mask);
275296

276297
oldsize = inode->i_size;
277298
/*
@@ -409,7 +430,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
409430
spin_lock(&fi->lock);
410431
fi->nlookup++;
411432
spin_unlock(&fi->lock);
412-
fuse_change_attributes(inode, attr, attr_valid, attr_version);
433+
fuse_change_attributes(inode, attr, NULL, attr_valid, attr_version);
413434

414435
return inode;
415436
}

fs/fuse/readdir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ static int fuse_direntplus_link(struct file *file,
223223
spin_unlock(&fi->lock);
224224

225225
forget_all_cached_acls(inode);
226-
fuse_change_attributes(inode, &o->attr,
226+
fuse_change_attributes(inode, &o->attr, NULL,
227227
ATTR_TIMEOUT(o),
228228
attr_version);
229229
/*

0 commit comments

Comments
 (0)