-
Notifications
You must be signed in to change notification settings - Fork 0
fs/9p: Reuse inode based on path (in addition to qid) #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: tmp-base
Are you sure you want to change the base?
Changes from all commits
de595c8
e1cf718
e01cb5a
1340f24
f029f5b
d2c865d
c3fa68a
893f80d
457ea0b
8e3bac8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,111 @@ | ||||||||||||||||||||||||||||||
// SPDX-License-Identifier: GPL-2.0-only | ||||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||||
* Specific operations on the v9fs_ino_path structure. | ||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||
* Copyright (C) 2025 by Tingmao Wang <m@maowtm.org> | ||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#include <linux/fs.h> | ||||||||||||||||||||||||||||||
#include <linux/string.h> | ||||||||||||||||||||||||||||||
#include <linux/dcache.h> | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#include <linux/posix_acl.h> | ||||||||||||||||||||||||||||||
#include <net/9p/9p.h> | ||||||||||||||||||||||||||||||
#include <net/9p/client.h> | ||||||||||||||||||||||||||||||
#include "v9fs.h" | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||||
* Must hold rename_sem due to traversing parents. Caller must hold | ||||||||||||||||||||||||||||||
* reference to dentry. | ||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||
struct v9fs_ino_path *make_ino_path(struct dentry *dentry) | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
struct v9fs_ino_path *path; | ||||||||||||||||||||||||||||||
size_t path_components = 0; | ||||||||||||||||||||||||||||||
struct dentry *curr = dentry; | ||||||||||||||||||||||||||||||
ssize_t i; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/* Either read or write lock held is ok */ | ||||||||||||||||||||||||||||||
lockdep_assert_held(&v9fs_dentry2v9ses(dentry)->rename_sem); | ||||||||||||||||||||||||||||||
might_sleep(); /* Allocation below might block */ | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
rcu_read_lock(); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/* Don't include the root dentry */ | ||||||||||||||||||||||||||||||
while (curr->d_parent != curr) { | ||||||||||||||||||||||||||||||
if (WARN_ON_ONCE(path_components >= SSIZE_MAX)) { | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comparison should use
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The condition checks against SSIZE_MAX but path_components is of type size_t (unsigned). This comparison will never be true since size_t cannot exceed SSIZE_MAX on most platforms, and the check should use SIZE_MAX instead.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comparison should use
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using SSIZE_MAX as the limit for path_components is incorrect since path_components is declared as size_t (unsigned). This comparison will never be true on most systems. Consider using SIZE_MAX or a more reasonable path depth limit. Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||
rcu_read_unlock(); | ||||||||||||||||||||||||||||||
return NULL; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
path_components++; | ||||||||||||||||||||||||||||||
curr = curr->d_parent; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||||
* Allocation can block so don't do it in RCU (and because the | ||||||||||||||||||||||||||||||
* allocation might be large, since name_snapshot leaves space for | ||||||||||||||||||||||||||||||
* inline str, not worth trying GFP_ATOMIC) | ||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||
rcu_read_unlock(); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
path = kmalloc(struct_size(path, names, path_components), GFP_KERNEL); | ||||||||||||||||||||||||||||||
if (!path) | ||||||||||||||||||||||||||||||
return NULL; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
path->nr_components = path_components; | ||||||||||||||||||||||||||||||
curr = dentry; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
rcu_read_lock(); | ||||||||||||||||||||||||||||||
for (i = path_components - 1; i >= 0; i--) { | ||||||||||||||||||||||||||||||
take_dentry_name_snapshot(&path->names[i], curr); | ||||||||||||||||||||||||||||||
curr = curr->d_parent; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
WARN_ON(curr != curr->d_parent); | ||||||||||||||||||||||||||||||
rcu_read_unlock(); | ||||||||||||||||||||||||||||||
return path; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
void free_ino_path(struct v9fs_ino_path *path) | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
if (path) { | ||||||||||||||||||||||||||||||
for (size_t i = 0; i < path->nr_components; i++) | ||||||||||||||||||||||||||||||
release_dentry_name_snapshot(&path->names[i]); | ||||||||||||||||||||||||||||||
kfree(path); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||||
* Must hold rename_sem due to traversing parents. Returns whether | ||||||||||||||||||||||||||||||
* ino_path matches with the path of a v9fs dentry. This function does | ||||||||||||||||||||||||||||||
* not sleep. | ||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||
bool ino_path_compare(struct v9fs_ino_path *ino_path, struct dentry *dentry) | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
struct dentry *curr = dentry; | ||||||||||||||||||||||||||||||
struct name_snapshot *compare; | ||||||||||||||||||||||||||||||
ssize_t i; | ||||||||||||||||||||||||||||||
bool ret; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
lockdep_assert_held_read(&v9fs_dentry2v9ses(dentry)->rename_sem); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
rcu_read_lock(); | ||||||||||||||||||||||||||||||
for (i = ino_path->nr_components - 1; i >= 0; i--) { | ||||||||||||||||||||||||||||||
Comment on lines
+88
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This loop uses a signed integer i (ssize_t) to iterate backwards from an unsigned value (size_t nr_components). When nr_components is 0, the loop will underflow and continue indefinitely since i starts at SIZE_MAX-1 and never becomes negative.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||
if (curr->d_parent == curr) { | ||||||||||||||||||||||||||||||
/* We're supposed to have more components to walk */ | ||||||||||||||||||||||||||||||
rcu_read_unlock(); | ||||||||||||||||||||||||||||||
return false; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
compare = &ino_path->names[i]; | ||||||||||||||||||||||||||||||
if (!d_same_name(curr, curr->d_parent, &compare->name)) { | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||
rcu_read_unlock(); | ||||||||||||||||||||||||||||||
return false; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
curr = curr->d_parent; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
/* Comparison fails if dentry is deeper than ino_path */ | ||||||||||||||||||||||||||||||
ret = (curr == curr->d_parent); | ||||||||||||||||||||||||||||||
rcu_read_unlock(); | ||||||||||||||||||||||||||||||
return ret; | ||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -36,7 +36,7 @@ enum { | |||||||||||||
/* Options that take integer arguments */ | ||||||||||||||
Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid, | ||||||||||||||
/* String options */ | ||||||||||||||
Opt_uname, Opt_remotename, Opt_cache, Opt_cachetag, | ||||||||||||||
Opt_uname, Opt_remotename, Opt_cache, Opt_cachetag, Opt_inodeident, | ||||||||||||||
/* Options that take no arguments */ | ||||||||||||||
Opt_nodevmap, Opt_noxattr, Opt_directio, Opt_ignoreqv, | ||||||||||||||
/* Access options */ | ||||||||||||||
|
@@ -63,6 +63,7 @@ static const match_table_t tokens = { | |||||||||||||
{Opt_access, "access=%s"}, | ||||||||||||||
{Opt_posixacl, "posixacl"}, | ||||||||||||||
{Opt_locktimeout, "locktimeout=%u"}, | ||||||||||||||
{Opt_inodeident, "inodeident=%s"}, | ||||||||||||||
{Opt_err, NULL} | ||||||||||||||
}; | ||||||||||||||
|
||||||||||||||
|
@@ -149,6 +150,21 @@ int v9fs_show_options(struct seq_file *m, struct dentry *root) | |||||||||||||
if (v9ses->flags & V9FS_NO_XATTR) | ||||||||||||||
seq_puts(m, ",noxattr"); | ||||||||||||||
|
||||||||||||||
switch (v9ses->flags & V9FS_INODE_IDENT_MASK) { | ||||||||||||||
case V9FS_INODE_IDENT_QID: | ||||||||||||||
seq_puts(m, ",inodeident=qid"); | ||||||||||||||
break; | ||||||||||||||
case V9FS_INODE_IDENT_PATH: | ||||||||||||||
seq_puts(m, ",inodeident=path"); | ||||||||||||||
break; | ||||||||||||||
default: | ||||||||||||||
/* | ||||||||||||||
* Unspecified, will be set later in v9fs_session_init depending on | ||||||||||||||
* cache setting | ||||||||||||||
*/ | ||||||||||||||
break; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
return p9_show_client_options(m, v9ses->clnt); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
|
@@ -369,6 +385,26 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) | |||||||||||||
v9ses->session_lock_timeout = (long)option * HZ; | ||||||||||||||
break; | ||||||||||||||
|
||||||||||||||
case Opt_inodeident: | ||||||||||||||
s = match_strdup(&args[0]); | ||||||||||||||
if (!s) { | ||||||||||||||
ret = -ENOMEM; | ||||||||||||||
p9_debug(P9_DEBUG_ERROR, | ||||||||||||||
"problem allocating copy of inodeident arg\n"); | ||||||||||||||
goto free_and_return; | ||||||||||||||
} | ||||||||||||||
v9ses->flags &= ~V9FS_INODE_IDENT_MASK; | ||||||||||||||
if (strcmp(s, "qid") == 0) { | ||||||||||||||
v9ses->flags |= V9FS_INODE_IDENT_QID; | ||||||||||||||
} else if (strcmp(s, "path") == 0) { | ||||||||||||||
v9ses->flags |= V9FS_INODE_IDENT_PATH; | ||||||||||||||
} else { | ||||||||||||||
ret = -EINVAL; | ||||||||||||||
p9_debug(P9_DEBUG_ERROR, "Unknown inodeident argument %s\n", s); | ||||||||||||||
} | ||||||||||||||
kfree(s); | ||||||||||||||
break; | ||||||||||||||
Comment on lines
+404
to
+406
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error handling should use
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||
|
||||||||||||||
default: | ||||||||||||||
continue; | ||||||||||||||
} | ||||||||||||||
|
@@ -393,6 +429,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||||||||||||
{ | ||||||||||||||
struct p9_fid *fid; | ||||||||||||||
int rc = -ENOMEM; | ||||||||||||||
bool cached; | ||||||||||||||
|
||||||||||||||
v9ses->uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL); | ||||||||||||||
if (!v9ses->uname) | ||||||||||||||
|
@@ -427,6 +464,26 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||||||||||||
if (rc < 0) | ||||||||||||||
goto err_clnt; | ||||||||||||||
|
||||||||||||||
cached = v9ses->cache & (CACHE_META | CACHE_LOOSE); | ||||||||||||||
|
||||||||||||||
if (cached && v9ses->flags & V9FS_INODE_IDENT_PATH) { | ||||||||||||||
rc = -EINVAL; | ||||||||||||||
p9_debug(P9_DEBUG_ERROR, | ||||||||||||||
"inodeident=path not supported in cached mode\n"); | ||||||||||||||
goto err_clnt; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
if (!(v9ses->flags & V9FS_INODE_IDENT_MASK)) { | ||||||||||||||
/* Unspecified - use default */ | ||||||||||||||
if (cached) { | ||||||||||||||
/* which is qid in cached mode (path not supported) */ | ||||||||||||||
v9ses->flags |= V9FS_INODE_IDENT_QID; | ||||||||||||||
} else { | ||||||||||||||
/* ...or path in uncached mode */ | ||||||||||||||
v9ses->flags |= V9FS_INODE_IDENT_PATH; | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; | ||||||||||||||
|
||||||||||||||
if (!v9fs_proto_dotl(v9ses) && | ||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comparison should use
SIZE_MAX
instead ofSSIZE_MAX
sincepath_components
is of typesize_t
(unsigned).SSIZE_MAX
is for signed types and may cause unexpected behavior.Copilot uses AI. Check for mistakes.