fuse: Allow stale time info for permission getattr#150
Conversation
|
LGTM |
437f393 to
96a9e59
Compare
|
Changed FUSE_GETATTR_PERM_CHECK to |
|
|
||
| forget_all_cached_acls(inode); | ||
| return fuse_do_getattr(inode, NULL, NULL); | ||
| return fuse_do_getattr(inode, NULL, NULL, true); |
There was a problem hiding this comment.
So here you basically want to pass in mask with STATX_MODE
There was a problem hiding this comment.
And actually that entire code path here will not be used if the file system supports statx
| } | ||
| } else { | ||
| err = fuse_do_getattr(inode, stat, file); | ||
| err = fuse_do_getattr(inode, stat, file, false); |
There was a problem hiding this comment.
A plain stat() shall not get time stamps?
Called in code path of
struct inode_operations::fuse_getattr
There was a problem hiding this comment.
why not? ... I'm more worried if we can somehow disable this behavior
There was a problem hiding this comment.
So you call 'stat file' and get random time stamp results?
There was a problem hiding this comment.
I don't think that manually called stat or readdir is the issue, but more like getattr from fuse in the middle of the code when it believes it needs to update something like mode for security reasons. And that is where statx then is the way to go - it was created exactly for that purpose. https://lkml.org/lkml/2016/11/17/382 , see
(3) Lightweight stat: Ask for just those details of interest, and allow a
netfs (such as NFS) to approximate anything not of interest, possibly
without going to the server [Trond Myklebust, Ulrich Drepper, Andreas
Dilger].
There was a problem hiding this comment.
So you call 'stat file' and get random time stamp results?
If that is what the customer wants, yes
There was a problem hiding this comment.
And why would the customer want to have random time stamps?
There was a problem hiding this comment.
Actually I read it wrong, here it false gets all attributes. Still, do don't it, but use statx
bsbernd
left a comment
There was a problem hiding this comment.
@cding-ddn I has to done like this
dir.c:int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask)
file.c: err = fuse_update_attributes(inode, iocb->ki_filp, STATX_SIZE);
file.c: err = fuse_update_attributes(mapping->host, file,
file.c: err = fuse_update_attributes(inode, file, STATX_SIZE);
file.c: retval = fuse_update_attributes(inode, file, STATX_SIZE);
fuse_i.h:int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask);
readdir.c: int err = fuse_update_attributes(inode, file, STATX_MTIME);
Bad hacks are not needed
|
I guess that actually the right flags are already mostly requested, some minor changes are needed. And then redfsd needs to support statx instead of a hack. |
| * Refresh and recalculate. | ||
| */ | ||
| ret = fuse_do_getattr(inode, NULL, file); | ||
| ret = fuse_do_getattr(inode, NULL, file, false); |
|
I actually thought that statx is not possible for some reason and that was the reason to do it like this. Implicit communication doesn't really work, I know. But if the whole reason is, that we don't want to support statx, then maybe we should and I agree with @bsbernd |
|
@cding-ddn we can probably close this |
This allows the FUSE server to acquire a weaker lock mode and reduce lock contention, specifically for shared directory file operations.
96a9e59 to
4d8c563
Compare
|
|
||
| forget_all_cached_acls(inode); | ||
| return fuse_do_getattr(inode, NULL, NULL); | ||
| return fuse_perm_do_statx(inode, NULL); |
There was a problem hiding this comment.
I think that can be much simpler, look at the caller of fuse_perm_getattr, i.e. fuse_permission
u32 perm_mask = STATX_MODE | STATX_UID | STATX_GID;
How about this
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 67581ce277b5..2ae36475e722 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1184,7 +1184,7 @@ static void fuse_statx_to_attr(struct fuse_statx *sx, struct fuse_attr *attr)
}
static int fuse_do_statx(struct inode *inode, struct file *file,
- struct kstat *stat)
+ struct kstat *stat, int sx_mask)
{
int err;
struct fuse_attr attr;
@@ -1206,7 +1206,7 @@ static int fuse_do_statx(struct inode *inode, struct file *file,
}
/* For now leave sync hints as the default, request all stats. */
inarg.sx_flags = 0;
- inarg.sx_mask = STATX_BASIC_STATS | STATX_BTIME;
+ inarg.sx_mask = sx_mask;
args.opcode = FUSE_STATX;
args.nodeid = get_node_id(inode);
args.in_numargs = 1;
@@ -1314,9 +1314,8 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
if (sync) {
forget_all_cached_acls(inode);
- /* Try statx if BTIME is requested */
- if (!fc->no_statx && (request_mask & ~STATX_BASIC_STATS)) {
- err = fuse_do_statx(inode, file, stat);
+ if (!fc->no_statx) {
+ err = fuse_do_statx(inode, file, stat, request_mask);
if (err == -ENOSYS) {
fc->no_statx = 1;
err = 0;
@@ -1478,13 +1477,13 @@ static int fuse_access(struct inode *inode, int mask)
return err;
}
-static int fuse_perm_getattr(struct inode *inode, int mask)
+static int fuse_perm_getattr(struct inode *inode, int mask, int perm_mask)
{
if (mask & MAY_NOT_BLOCK)
return -ECHILD;
forget_all_cached_acls(inode);
- return fuse_do_getattr(inode, NULL, NULL);
+ return fuse_update_get_attr(inode, NULL, NULL, perm_mask, AT_STATX_FORCE_SYNC);
}
/*
@@ -1506,6 +1505,7 @@ static int fuse_permission(struct mnt_idmap *idmap,
struct fuse_conn *fc = get_fuse_conn(inode);
bool refreshed = false;
int err = 0;
+ int perm_mask = STATX_MODE | STATX_UID | STATX_GID;
if (fuse_is_bad(inode))
return -EIO;
@@ -1519,13 +1519,12 @@ static int fuse_permission(struct mnt_idmap *idmap,
if (fc->default_permissions ||
((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) {
struct fuse_inode *fi = get_fuse_inode(inode);
- u32 perm_mask = STATX_MODE | STATX_UID | STATX_GID;
if (perm_mask & READ_ONCE(fi->inval_mask) ||
time_before64(fi->i_time, get_jiffies_64())) {
refreshed = true;
- err = fuse_perm_getattr(inode, mask);
+ err = fuse_perm_getattr(inode, mask, perm_mask);
if (err)
return err;
}
@@ -1538,7 +1537,7 @@ static int fuse_permission(struct mnt_idmap *idmap,
attributes. This is also needed, because the root
node will at first have no permissions */
if (err == -EACCES && !refreshed) {
- err = fuse_perm_getattr(inode, mask);
+ err = fuse_perm_getattr(inode, mask, perm_mask);
if (!err)
err = generic_permission(&nop_mnt_idmap,
inode, mask);
@@ -1555,7 +1554,7 @@ static int fuse_permission(struct mnt_idmap *idmap,
if (refreshed)
return -EACCES;
- err = fuse_perm_getattr(inode, mask);
+ err = fuse_perm_getattr(inode, mask, perm_mask);
if (!err && !(inode->i_mode & S_IXUGO))
return -EACCES;
}
Sorry, only noticed past midnight when I was just on my way to bed - the above is not even compilation tested.
Basically this passes in the request mask to fuse_statx_to_attr() and uses that function in fuse_perm_getattr() via fuse_update_get_attr().
I don't know if Miklos will accept it like this, but I don't think he can reject it entirely either, because as I said before, one of the reasons to create statx was the network file system case with a request mask - the file system is obliged to fill in the requested arguments, but is free to fill in more.
There was a problem hiding this comment.
With "much simpler" I actually mean "without code dup".
There was a problem hiding this comment.
Yes, but that may cause problem when we cherry-pick upstream kernel changes later.
There was a problem hiding this comment.
I mean my change intentionally does not modify the existing kernel routine signature.
There was a problem hiding this comment.
Obviously we need to send my suggestion upstream.
There was a problem hiding this comment.
@bsbernd The suggested code fails to improve performance; fuse_do_statx() does not invoke redfs_change_attributes() for the requested mask STATX_MODE | STATX_UID | STATX_GID.
|
We are going to use #151 |
This allows the FUSE server to acquire a weaker lock mode and reduce
lock contention, specifically for shared directory file operations.