* [patches][cft] ufs stuff
@ 2023-12-13 3:16 Al Viro
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
2023-12-13 6:53 ` [patches][cft] ufs stuff Al Viro
0 siblings, 2 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:16 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
More old stuff, this time UFS one. Part of that is
yet another kmap_local_page() conversion, part - assorted
cleanups.
It seems to survive local beating, but it needs
more review and testing.
The branch is available in vfs.git #work.ufs; individual patches
in followups.
Shortlog:
Al Viro (8):
ufs: fix handling of delete_entry and set_link failures
ufs: untangle ubh_...block...() macros, part 1
ufs: untangle ubh_...block...(), part 2
ufs: untangle ubh_...block...(), part 3
ufs_clusteracct(): switch to passing fragment number
ufs_inode_getfrag(): remove junk comment
ufs: get rid of ubh_{ubhcpymem,memcpyubh}()
clean ufs_trunc_direct() up a bit...
Fabio M. De Francesco (4):
fs/ufs: Use the offset_in_page() helper
fs/ufs: Change the signature of ufs_get_page()
fs/ufs: Use ufs_put_page() in ufs_rename()
fs/ufs: Replace kmap() with kmap_local_page()
Diffstat:
fs/ufs/balloc.c | 29 +++++------
fs/ufs/dir.c | 156 +++++++++++++++++++++++++++++---------------------------
fs/ufs/inode.c | 144 ++++++++++++++++++++++-----------------------------
fs/ufs/namei.c | 52 ++++++++-----------
fs/ufs/super.c | 45 ++++++----------
fs/ufs/ufs.h | 2 +-
fs/ufs/util.c | 46 -----------------
fs/ufs/util.h | 61 +++++++++++-----------
8 files changed, 222 insertions(+), 313 deletions(-)
Beginning of the series is the kmap_local_page() conversion and
fixes, parallel to what's been done for sysv/ext2/minixfs:
1/12) fs/ufs: Use the offset_in_page() helper
2/12) fs/ufs: Change the signature of ufs_get_page()
3/12) fs/ufs: Use ufs_put_page() in ufs_rename()
4/12) fs/ufs: Replace kmap() with kmap_local_page()
5/12) ufs: fix handling of delete_entry and set_link failures
After that it's assorted cleanups; there's quite a bit of obfuscation
caused by trying to hide the fragment numbers behind a forest of
macros, presumably in attempt to make it more similar to ext2 et.al.
These patches untangle some of that.
6/12) ufs: untangle ubh_...block...() macros, part 1
passing implicit argument to a macro by having it in a variable
with special name is Not Nice(tm); just pass it explicitly.
kill an unused macro, while we are at it...
7/12) ufs: untangle ubh_...block...(), part 2
pass cylinder group descriptor instead of its buffer head (ubh,
always UCPI_UBH(ucpi)) and its ->c_freeoff.
8/12) ufs: untangle ubh_...block...(), part 3
Pass fragment number instead of a block one. It's available in all
callers and it makes the logics inside those helpers much simpler.
The bitmap they operate upon is with bit per fragment, block being
an aligned group of 1, 2, 4 or 8 adjacent fragments. We still
need a switch by the number of fragments in block (== number of
bits to check/set/clear), but finding the byte we need to work
with becomes uniform and that makes the things easier to follow.
9/12) ufs_clusteracct(): switch to passing fragment number
10/12) ufs_inode_getfrag(): remove junk comment
It used to be a stubbed out beginning of ufs2 support, which had
been implemented differently quite a while ago. Remove the
commented-out (pseudo-)code.
11/12) ufs: get rid of ubh_{ubhcpymem,memcpyubh}()
used only in ufs_read_cylinder_structures()/ufs_put_super_internal()
and there we can just as well avoid bothering with ufs_buffer_head
and just deal with it fragment-by-fragment.
12/12) clean ufs_trunc_direct() up a bit...
For short files (== no indirect blocks needed) UFS allows the last
block to be a partial one. That creates some complications for
truncation down to "short file" lengths. ufs_trunc_direct() is
called when we'd already made sure that new EOF is not in a hole;
nothing needs to be done if we are extending the file and in
case we are shrinking the file it needs to
* shrink or free the old final block.
* free all full direct blocks between the new and old EOF.
* possibly shrink the new final block.
The logics is needlessly complicated by trying to keep all cases
handled by the same sequence of operations.
if not shrinking
nothing to do
else if number of full blocks unchanged
free the tail of possibly partial last block
else
free the tail of (full) new last block
free all present (full) blocks in between
free the (possibly partial) old last block
is easier to follow than the result of trying to unify these
cases.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 01/12] fs/ufs: Use the offset_in_page() helper
2023-12-13 3:16 [patches][cft] ufs stuff Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 02/12] fs/ufs: Change the signature of ufs_get_page() Al Viro
` (10 more replies)
2023-12-13 6:53 ` [patches][cft] ufs stuff Al Viro
1 sibling, 11 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
From: "Fabio M. De Francesco" <fmdefrancesco@gmail.com>
Use the offset_in_page() helper because it is more suitable than doing
explicit subtractions between pointers to directory entries and kernel
virtual addresses of mapped pages.
Cc: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Fabio M. De Francesco <fmdefrancesco@gmail.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/dir.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 27c85d92d1dc..5be536fe0e3f 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -92,8 +92,7 @@ void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
struct page *page, struct inode *inode,
bool update_times)
{
- loff_t pos = page_offset(page) +
- (char *) de - (char *) page_address(page);
+ loff_t pos = page_offset(page) + offset_in_page(de);
unsigned len = fs16_to_cpu(dir->i_sb, de->d_reclen);
int err;
@@ -377,8 +376,7 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode)
return -EINVAL;
got_it:
- pos = page_offset(page) +
- (char*)de - (char*)page_address(page);
+ pos = page_offset(page) + offset_in_page(de);
err = ufs_prepare_chunk(page, pos, rec_len);
if (err)
goto out_unlock;
@@ -504,8 +502,8 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
{
struct super_block *sb = inode->i_sb;
char *kaddr = page_address(page);
- unsigned from = ((char*)dir - kaddr) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);
- unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen);
+ unsigned int from = offset_in_page(dir) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);
+ unsigned int to = offset_in_page(dir) + fs16_to_cpu(sb, dir->d_reclen);
loff_t pos;
struct ufs_dir_entry *pde = NULL;
struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from);
@@ -529,7 +527,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
de = ufs_next_entry(sb, de);
}
if (pde)
- from = (char*)pde - (char*)page_address(page);
+ from = offset_in_page(pde);
pos = page_offset(page) + from;
lock_page(page);
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 02/12] fs/ufs: Change the signature of ufs_get_page()
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 03/12] fs/ufs: Use ufs_put_page() in ufs_rename() Al Viro
` (9 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
From: "Fabio M. De Francesco" <fmdefrancesco@gmail.com>
Change the signature of ufs_get_page() in order to prepare this function
to the conversion to the use of kmap_local_page(). Change also those call
sites which are required to conform its invocations to the new
signature.
Cc: Ira Weiny <ira.weiny@intel.com>
Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Fabio M. De Francesco <fmdefrancesco@gmail.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/dir.c | 49 +++++++++++++++++++++----------------------------
1 file changed, 21 insertions(+), 28 deletions(-)
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 5be536fe0e3f..b695eab0105a 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -191,7 +191,7 @@ static bool ufs_check_page(struct page *page)
return false;
}
-static struct page *ufs_get_page(struct inode *dir, unsigned long n)
+static void *ufs_get_page(struct inode *dir, unsigned long n, struct page **p)
{
struct address_space *mapping = dir->i_mapping;
struct page *page = read_mapping_page(mapping, n, NULL);
@@ -201,8 +201,10 @@ static struct page *ufs_get_page(struct inode *dir, unsigned long n)
if (!ufs_check_page(page))
goto fail;
}
+ *p = page;
+ return page_address(page);
}
- return page;
+ return ERR_CAST(page);
fail:
ufs_put_page(page);
@@ -233,15 +235,12 @@ ufs_next_entry(struct super_block *sb, struct ufs_dir_entry *p)
struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct page **p)
{
- struct page *page = ufs_get_page(dir, 0);
- struct ufs_dir_entry *de = NULL;
+ struct ufs_dir_entry *de = ufs_get_page(dir, 0, p);
- if (!IS_ERR(page)) {
- de = ufs_next_entry(dir->i_sb,
- (struct ufs_dir_entry *)page_address(page));
- *p = page;
- }
- return de;
+ if (!IS_ERR(de))
+ return ufs_next_entry(dir->i_sb, de);
+ else
+ return NULL;
}
/*
@@ -279,11 +278,10 @@ struct ufs_dir_entry *ufs_find_entry(struct inode *dir, const struct qstr *qstr,
start = 0;
n = start;
do {
- char *kaddr;
- page = ufs_get_page(dir, n);
- if (!IS_ERR(page)) {
- kaddr = page_address(page);
- de = (struct ufs_dir_entry *) kaddr;
+ char *kaddr = ufs_get_page(dir, n, &page);
+
+ if (!IS_ERR(kaddr)) {
+ de = (struct ufs_dir_entry *)kaddr;
kaddr += ufs_last_byte(dir, n) - reclen;
while ((char *) de <= kaddr) {
if (ufs_match(sb, namelen, name, de))
@@ -334,12 +332,10 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode)
for (n = 0; n <= npages; n++) {
char *dir_end;
- page = ufs_get_page(dir, n);
- err = PTR_ERR(page);
- if (IS_ERR(page))
- goto out;
+ kaddr = ufs_get_page(dir, n, &page);
+ if (IS_ERR(kaddr))
+ return PTR_ERR(kaddr);
lock_page(page);
- kaddr = page_address(page);
dir_end = kaddr + ufs_last_byte(dir, n);
de = (struct ufs_dir_entry *)kaddr;
kaddr += PAGE_SIZE - reclen;
@@ -402,7 +398,6 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode)
/* OFFSET_CACHE */
out_put:
ufs_put_page(page);
-out:
return err;
out_unlock:
unlock_page(page);
@@ -445,17 +440,16 @@ ufs_readdir(struct file *file, struct dir_context *ctx)
for ( ; n < npages; n++, offset = 0) {
char *kaddr, *limit;
struct ufs_dir_entry *de;
+ struct page *page;
- struct page *page = ufs_get_page(inode, n);
-
- if (IS_ERR(page)) {
+ kaddr = ufs_get_page(inode, n, &page);
+ if (IS_ERR(kaddr)) {
ufs_error(sb, __func__,
"bad page in #%lu",
inode->i_ino);
ctx->pos += PAGE_SIZE - offset;
return -EIO;
}
- kaddr = page_address(page);
if (unlikely(need_revalidate)) {
if (offset) {
offset = ufs_validate_entry(sb, kaddr, offset, chunk_mask);
@@ -604,12 +598,11 @@ int ufs_empty_dir(struct inode * inode)
for (i = 0; i < npages; i++) {
char *kaddr;
struct ufs_dir_entry *de;
- page = ufs_get_page(inode, i);
- if (IS_ERR(page))
+ kaddr = ufs_get_page(inode, i, &page);
+ if (IS_ERR(kaddr))
continue;
- kaddr = page_address(page);
de = (struct ufs_dir_entry *)kaddr;
kaddr += ufs_last_byte(inode, i) - UFS_DIR_REC_LEN(1);
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 03/12] fs/ufs: Use ufs_put_page() in ufs_rename()
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
2023-12-13 3:18 ` [PATCH 02/12] fs/ufs: Change the signature of ufs_get_page() Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 04/12] fs/ufs: Replace kmap() with kmap_local_page() Al Viro
` (8 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
From: "Fabio M. De Francesco" <fmdefrancesco@gmail.com>
Use the ufs_put_page() helper in ufs_rename() instead of open-coding three
kunmap() + put_page().
Cc: Al Viro <viro@zeniv.linux.org.uk>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Suggested-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Fabio M. De Francesco <fmdefrancesco@gmail.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/dir.c | 2 +-
fs/ufs/namei.c | 9 +++------
fs/ufs/ufs.h | 1 +
3 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index b695eab0105a..2c9061ad3ab3 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -66,7 +66,7 @@ static int ufs_handle_dirsync(struct inode *dir)
return err;
}
-static inline void ufs_put_page(struct page *page)
+inline void ufs_put_page(struct page *page)
{
kunmap(page);
put_page(page);
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 9cad29463791..50dbe13d24d6 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -307,8 +307,7 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
if (old_dir != new_dir)
ufs_set_link(old_inode, dir_de, dir_page, new_dir, 0);
else {
- kunmap(dir_page);
- put_page(dir_page);
+ ufs_put_page(dir_page);
}
inode_dec_link_count(old_dir);
}
@@ -317,12 +316,10 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
out_dir:
if (dir_de) {
- kunmap(dir_page);
- put_page(dir_page);
+ ufs_put_page(dir_page);
}
out_old:
- kunmap(old_page);
- put_page(old_page);
+ ufs_put_page(old_page);
out:
return err;
}
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h
index 6b499180643b..4594cbe6b2e0 100644
--- a/fs/ufs/ufs.h
+++ b/fs/ufs/ufs.h
@@ -98,6 +98,7 @@ extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, uns
extern void ufs_put_cylinder (struct super_block *, unsigned);
/* dir.c */
+extern void ufs_put_page(struct page *page);
extern const struct inode_operations ufs_dir_inode_operations;
extern int ufs_add_link (struct dentry *, struct inode *);
extern ino_t ufs_inode_by_name(struct inode *, const struct qstr *);
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 04/12] fs/ufs: Replace kmap() with kmap_local_page()
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
2023-12-13 3:18 ` [PATCH 02/12] fs/ufs: Change the signature of ufs_get_page() Al Viro
2023-12-13 3:18 ` [PATCH 03/12] fs/ufs: Use ufs_put_page() in ufs_rename() Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 05/12] ufs: fix handling of delete_entry and set_link failures Al Viro
` (7 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
From: "Fabio M. De Francesco" <fmdefrancesco@gmail.com>
kmap() is being deprecated in favor of kmap_local_page().
There are two main problems with kmap(): (1) It comes with an overhead as
the mapping space is restricted and protected by a global lock for
synchronization and (2) it also requires global TLB invalidation when the
kmap’s pool wraps and it might block when the mapping space is fully
utilized until a slot becomes available.
With kmap_local_page() the mappings are per thread, CPU local, can take
page faults, and can be called from any context (including interrupts).
It is faster than kmap() in kernels with HIGHMEM enabled. Furthermore,
the tasks can be preempted and, when they are scheduled to run again, the
kernel virtual addresses are restored and still valid.
The use of kmap_local_page() in fs/ufs is "safe" because (1) the kernel
virtual addresses are exclusively re-used by the thread which
established the mappings (i.e., thread locality is never violated) and (2)
the nestings of mappings and un-mappings are always stack based (LIFO).
Therefore, replace kmap() with kmap_local_page() in fs/ufs. kunmap_local()
requires the mapping address, so return that address from ufs_get_page()
and use it as parameter for the second argument of ufs_put_page().
[AV: replaced ufs_put_page() with unmap_and_put() - there's nothing
ufs-specific about it]
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Suggested-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Fabio M. De Francesco <fmdefrancesco@gmail.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/dir.c | 74 +++++++++++++++++++++++++++++++-------------------
fs/ufs/namei.c | 11 ++++----
fs/ufs/ufs.h | 1 -
3 files changed, 51 insertions(+), 35 deletions(-)
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 2c9061ad3ab3..fcf13e3ca869 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -66,12 +66,6 @@ static int ufs_handle_dirsync(struct inode *dir)
return err;
}
-inline void ufs_put_page(struct page *page)
-{
- kunmap(page);
- put_page(page);
-}
-
ino_t ufs_inode_by_name(struct inode *dir, const struct qstr *qstr)
{
ino_t res = 0;
@@ -81,7 +75,7 @@ ino_t ufs_inode_by_name(struct inode *dir, const struct qstr *qstr)
de = ufs_find_entry(dir, qstr, &page);
if (de) {
res = fs32_to_cpu(dir->i_sb, de->d_ino);
- ufs_put_page(page);
+ unmap_and_put_page(page, de);
}
return res;
}
@@ -104,7 +98,7 @@ void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
ufs_set_de_type(dir->i_sb, de, inode->i_mode);
ufs_commit_chunk(page, pos, len);
- ufs_put_page(page);
+ unmap_and_put_page(page, de);
if (update_times)
inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
mark_inode_dirty(dir);
@@ -112,11 +106,10 @@ void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
}
-static bool ufs_check_page(struct page *page)
+static bool ufs_check_page(struct page *page, char *kaddr)
{
struct inode *dir = page->mapping->host;
struct super_block *sb = dir->i_sb;
- char *kaddr = page_address(page);
unsigned offs, rec_len;
unsigned limit = PAGE_SIZE;
const unsigned chunk_mask = UFS_SB(sb)->s_uspi->s_dirblksize - 1;
@@ -191,23 +184,32 @@ static bool ufs_check_page(struct page *page)
return false;
}
+/*
+ * Calls to ufs_get_page()/unmap_and_put_page() must be nested according to the
+ * rules documented in kmap_local_page()/kunmap_local().
+ *
+ * NOTE: ufs_find_entry() and ufs_dotdot() act as calls to ufs_get_page()
+ * and must be treated accordingly for nesting purposes.
+ */
static void *ufs_get_page(struct inode *dir, unsigned long n, struct page **p)
{
+ char *kaddr;
+
struct address_space *mapping = dir->i_mapping;
struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
- kmap(page);
+ kaddr = kmap_local_page(page);
if (unlikely(!PageChecked(page))) {
- if (!ufs_check_page(page))
+ if (!ufs_check_page(page, kaddr))
goto fail;
}
*p = page;
- return page_address(page);
+ return kaddr;
}
return ERR_CAST(page);
fail:
- ufs_put_page(page);
+ unmap_and_put_page(page, kaddr);
return ERR_PTR(-EIO);
}
@@ -233,6 +235,13 @@ ufs_next_entry(struct super_block *sb, struct ufs_dir_entry *p)
fs16_to_cpu(sb, p->d_reclen));
}
+/*
+ * Calls to ufs_get_page()/unmap_and_put_page() must be nested according to the
+ * rules documented in kmap_local_page()/kunmap_local().
+ *
+ * ufs_dotdot() acts as a call to ufs_get_page() and must be treated
+ * accordingly for nesting purposes.
+ */
struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct page **p)
{
struct ufs_dir_entry *de = ufs_get_page(dir, 0, p);
@@ -250,6 +259,11 @@ struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct page **p)
* returns the page in which the entry was found, and the entry itself
* (as a parameter - res_dir). Page is returned mapped and unlocked.
* Entry is guaranteed to be valid.
+ *
+ * On Success unmap_and_put_page() should be called on *res_page.
+ *
+ * ufs_find_entry() acts as a call to ufs_get_page() and must be treated
+ * accordingly for nesting purposes.
*/
struct ufs_dir_entry *ufs_find_entry(struct inode *dir, const struct qstr *qstr,
struct page **res_page)
@@ -288,7 +302,7 @@ struct ufs_dir_entry *ufs_find_entry(struct inode *dir, const struct qstr *qstr,
goto found;
de = ufs_next_entry(sb, de);
}
- ufs_put_page(page);
+ unmap_and_put_page(page, kaddr);
}
if (++n >= npages)
n = 0;
@@ -366,7 +380,7 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode)
de = (struct ufs_dir_entry *) ((char *) de + rec_len);
}
unlock_page(page);
- ufs_put_page(page);
+ unmap_and_put_page(page, kaddr);
}
BUG();
return -EINVAL;
@@ -397,7 +411,7 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode)
err = ufs_handle_dirsync(dir);
/* OFFSET_CACHE */
out_put:
- ufs_put_page(page);
+ unmap_and_put_page(page, kaddr);
return err;
out_unlock:
unlock_page(page);
@@ -475,13 +489,13 @@ ufs_readdir(struct file *file, struct dir_context *ctx)
ufs_get_de_namlen(sb, de),
fs32_to_cpu(sb, de->d_ino),
d_type)) {
- ufs_put_page(page);
+ unmap_and_put_page(page, kaddr);
return 0;
}
}
ctx->pos += fs16_to_cpu(sb, de->d_reclen);
}
- ufs_put_page(page);
+ unmap_and_put_page(page, kaddr);
}
return 0;
}
@@ -492,10 +506,15 @@ ufs_readdir(struct file *file, struct dir_context *ctx)
* previous entry.
*/
int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
- struct page * page)
+ struct page *page)
{
struct super_block *sb = inode->i_sb;
- char *kaddr = page_address(page);
+ /*
+ * The "dir" dentry points somewhere in the same page whose we need the
+ * address of; therefore, we can simply get the base address "kaddr" by
+ * masking the previous with PAGE_MASK.
+ */
+ char *kaddr = (char *)((unsigned long)dir & PAGE_MASK);
unsigned int from = offset_in_page(dir) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);
unsigned int to = offset_in_page(dir) + fs16_to_cpu(sb, dir->d_reclen);
loff_t pos;
@@ -535,7 +554,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
mark_inode_dirty(inode);
err = ufs_handle_dirsync(inode);
out:
- ufs_put_page(page);
+ unmap_and_put_page(page, kaddr);
UFSD("EXIT\n");
return err;
}
@@ -559,8 +578,7 @@ int ufs_make_empty(struct inode * inode, struct inode *dir)
goto fail;
}
- kmap(page);
- base = (char*)page_address(page);
+ base = kmap_local_page(page);
memset(base, 0, PAGE_SIZE);
de = (struct ufs_dir_entry *) base;
@@ -577,7 +595,7 @@ int ufs_make_empty(struct inode * inode, struct inode *dir)
de->d_reclen = cpu_to_fs16(sb, chunk_size - UFS_DIR_REC_LEN(1));
ufs_set_de_namlen(sb, de, 2);
strcpy (de->d_name, "..");
- kunmap(page);
+ kunmap_local(base);
ufs_commit_chunk(page, 0, chunk_size);
err = ufs_handle_dirsync(inode);
@@ -594,9 +612,9 @@ int ufs_empty_dir(struct inode * inode)
struct super_block *sb = inode->i_sb;
struct page *page = NULL;
unsigned long i, npages = dir_pages(inode);
+ char *kaddr;
for (i = 0; i < npages; i++) {
- char *kaddr;
struct ufs_dir_entry *de;
kaddr = ufs_get_page(inode, i, &page);
@@ -629,12 +647,12 @@ int ufs_empty_dir(struct inode * inode)
}
de = ufs_next_entry(sb, de);
}
- ufs_put_page(page);
+ unmap_and_put_page(page, kaddr);
}
return 1;
not_empty:
- ufs_put_page(page);
+ unmap_and_put_page(page, kaddr);
return 0;
}
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 50dbe13d24d6..25fa97340f73 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -250,7 +250,7 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry);
struct page *dir_page = NULL;
- struct ufs_dir_entry * dir_de = NULL;
+ struct ufs_dir_entry *dir_de = NULL;
struct page *old_page;
struct ufs_dir_entry *old_de;
int err = -ENOENT;
@@ -307,7 +307,7 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
if (old_dir != new_dir)
ufs_set_link(old_inode, dir_de, dir_page, new_dir, 0);
else {
- ufs_put_page(dir_page);
+ unmap_and_put_page(dir_page, dir_de);
}
inode_dec_link_count(old_dir);
}
@@ -315,11 +315,10 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
out_dir:
- if (dir_de) {
- ufs_put_page(dir_page);
- }
+ if (dir_de)
+ unmap_and_put_page(dir_page, dir_de);
out_old:
- ufs_put_page(old_page);
+ unmap_and_put_page(old_page, old_de);
out:
return err;
}
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h
index 4594cbe6b2e0..6b499180643b 100644
--- a/fs/ufs/ufs.h
+++ b/fs/ufs/ufs.h
@@ -98,7 +98,6 @@ extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, uns
extern void ufs_put_cylinder (struct super_block *, unsigned);
/* dir.c */
-extern void ufs_put_page(struct page *page);
extern const struct inode_operations ufs_dir_inode_operations;
extern int ufs_add_link (struct dentry *, struct inode *);
extern ino_t ufs_inode_by_name(struct inode *, const struct qstr *);
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 05/12] ufs: fix handling of delete_entry and set_link failures
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
` (2 preceding siblings ...)
2023-12-13 3:18 ` [PATCH 04/12] fs/ufs: Replace kmap() with kmap_local_page() Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 06/12] ufs: untangle ubh_...block...() macros, part 1 Al Viro
` (6 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
similar to minixfs series - make ufs_set_link() report failures,
lift dir_put_page() into the callers of ufs_set_link() and
ufs_delete_entry(), make ufs_rename() handle failures in both.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/dir.c | 27 ++++++++++++---------------
fs/ufs/namei.c | 40 +++++++++++++++++-----------------------
fs/ufs/ufs.h | 2 +-
3 files changed, 30 insertions(+), 39 deletions(-)
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index fcf13e3ca869..5edacece384b 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -81,8 +81,7 @@ ino_t ufs_inode_by_name(struct inode *dir, const struct qstr *qstr)
}
-/* Releases the page */
-void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
+int ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
struct page *page, struct inode *inode,
bool update_times)
{
@@ -92,17 +91,19 @@ void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
lock_page(page);
err = ufs_prepare_chunk(page, pos, len);
- BUG_ON(err);
+ if (unlikely(err)) {
+ unlock_page(page);
+ return err;
+ }
de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);
ufs_set_de_type(dir->i_sb, de, inode->i_mode);
ufs_commit_chunk(page, pos, len);
- unmap_and_put_page(page, de);
if (update_times)
inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
mark_inode_dirty(dir);
- ufs_handle_dirsync(dir);
+ return ufs_handle_dirsync(dir);
}
@@ -522,8 +523,6 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from);
int err;
- UFSD("ENTER\n");
-
UFSD("ino %u, reclen %u, namlen %u, name %s\n",
fs32_to_cpu(sb, de->d_ino),
fs16_to_cpu(sb, de->d_reclen),
@@ -533,8 +532,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
if (de->d_reclen == 0) {
ufs_error(inode->i_sb, __func__,
"zero-length directory entry");
- err = -EIO;
- goto out;
+ return -EIO;
}
pde = de;
de = ufs_next_entry(sb, de);
@@ -545,18 +543,17 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
pos = page_offset(page) + from;
lock_page(page);
err = ufs_prepare_chunk(page, pos, to - from);
- BUG_ON(err);
+ if (unlikely(err)) {
+ unlock_page(page);
+ return err;
+ }
if (pde)
pde->d_reclen = cpu_to_fs16(sb, to - from);
dir->d_ino = 0;
ufs_commit_chunk(page, pos, to - from);
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
mark_inode_dirty(inode);
- err = ufs_handle_dirsync(inode);
-out:
- unmap_and_put_page(page, kaddr);
- UFSD("EXIT\n");
- return err;
+ return ufs_handle_dirsync(inode);
}
int ufs_make_empty(struct inode * inode, struct inode *dir)
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 25fa97340f73..b8082fb53a08 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -210,20 +210,18 @@ static int ufs_unlink(struct inode *dir, struct dentry *dentry)
struct inode * inode = d_inode(dentry);
struct ufs_dir_entry *de;
struct page *page;
- int err = -ENOENT;
+ int err;
de = ufs_find_entry(dir, &dentry->d_name, &page);
if (!de)
- goto out;
+ return -ENOENT;
err = ufs_delete_entry(dir, de, page);
- if (err)
- goto out;
-
- inode_set_ctime_to_ts(inode, inode_get_ctime(dir));
- inode_dec_link_count(inode);
- err = 0;
-out:
+ if (!err) {
+ inode_set_ctime_to_ts(inode, inode_get_ctime(dir));
+ inode_dec_link_count(inode);
+ }
+ unmap_and_put_page(page, de);
return err;
}
@@ -253,14 +251,14 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
struct ufs_dir_entry *dir_de = NULL;
struct page *old_page;
struct ufs_dir_entry *old_de;
- int err = -ENOENT;
+ int err;
if (flags & ~RENAME_NOREPLACE)
return -EINVAL;
old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page);
if (!old_de)
- goto out;
+ return -ENOENT;
if (S_ISDIR(old_inode->i_mode)) {
err = -EIO;
@@ -281,7 +279,10 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
new_de = ufs_find_entry(new_dir, &new_dentry->d_name, &new_page);
if (!new_de)
goto out_dir;
- ufs_set_link(new_dir, new_de, new_page, old_inode, 1);
+ err = ufs_set_link(new_dir, new_de, new_page, old_inode, 1);
+ unmap_and_put_page(new_page, new_de);
+ if (err)
+ goto out_dir;
inode_set_ctime_current(new_inode);
if (dir_de)
drop_nlink(new_inode);
@@ -299,27 +300,20 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
* rename.
*/
inode_set_ctime_current(old_inode);
-
- ufs_delete_entry(old_dir, old_de, old_page);
mark_inode_dirty(old_inode);
- if (dir_de) {
+ err = ufs_delete_entry(old_dir, old_de, old_page);
+ if (!err && dir_de) {
if (old_dir != new_dir)
- ufs_set_link(old_inode, dir_de, dir_page, new_dir, 0);
- else {
- unmap_and_put_page(dir_page, dir_de);
- }
+ err = ufs_set_link(old_inode, dir_de, dir_page,
+ new_dir, 0);
inode_dec_link_count(old_dir);
}
- return 0;
-
-
out_dir:
if (dir_de)
unmap_and_put_page(dir_page, dir_de);
out_old:
unmap_and_put_page(old_page, old_de);
-out:
return err;
}
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h
index 6b499180643b..b521ab01471a 100644
--- a/fs/ufs/ufs.h
+++ b/fs/ufs/ufs.h
@@ -106,7 +106,7 @@ extern struct ufs_dir_entry *ufs_find_entry(struct inode *, const struct qstr *,
extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *);
extern int ufs_empty_dir (struct inode *);
extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **);
-extern void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
+extern int ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
struct page *page, struct inode *inode, bool update_times);
/* file.c */
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 06/12] ufs: untangle ubh_...block...() macros, part 1
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
` (3 preceding siblings ...)
2023-12-13 3:18 ` [PATCH 05/12] ufs: fix handling of delete_entry and set_link failures Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 07/12] ufs: untangle ubh_...block...(), part 2 Al Viro
` (5 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
passing implicit argument to a macro by having it in a variable
with special name is Not Nice(tm); just pass it explicitly.
kill an unused macro, while we are at it...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/balloc.c | 10 +++++-----
fs/ufs/util.h | 11 +++--------
2 files changed, 8 insertions(+), 13 deletions(-)
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index 53c11be2b2c1..e412ddcfda03 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -95,7 +95,7 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
* Trying to reassemble free fragments into block
*/
blkno = ufs_fragstoblks (bbase);
- if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
+ if (ubh_isblockset(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
uspi->cs_total.cs_nffree -= uspi->s_fpb;
fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
@@ -182,10 +182,10 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
for (i = bit; i < end_bit; i += uspi->s_fpb) {
blkno = ufs_fragstoblks(i);
- if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
+ if (ubh_isblockset(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
}
- ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
+ ubh_setblock(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, 1);
@@ -716,7 +716,7 @@ static u64 ufs_alloccg_block(struct inode *inode,
/*
* If the requested block is available, use it.
*/
- if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
+ if (ubh_isblockset(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
result = goal;
goto gotit;
}
@@ -730,7 +730,7 @@ static u64 ufs_alloccg_block(struct inode *inode,
if (!try_add_frags(inode, uspi->s_fpb))
return 0;
blkno = ufs_fragstoblks(result);
- ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
+ ubh_clrblock(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, -1);
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 0ecd2ed792f5..dc3240f0ddea 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -455,10 +455,7 @@ static inline unsigned _ubh_find_last_zero_bit_(
return (base << uspi->s_bpfshift) + pos - begin;
}
-#define ubh_isblockclear(ubh,begin,block) (!_ubh_isblockset_(uspi,ubh,begin,block))
-
-#define ubh_isblockset(ubh,begin,block) _ubh_isblockset_(uspi,ubh,begin,block)
-static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi,
+static inline int ubh_isblockset(struct ufs_sb_private_info * uspi,
struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
{
u8 mask;
@@ -478,8 +475,7 @@ static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi,
return 0;
}
-#define ubh_clrblock(ubh,begin,block) _ubh_clrblock_(uspi,ubh,begin,block)
-static inline void _ubh_clrblock_(struct ufs_sb_private_info * uspi,
+static inline void ubh_clrblock(struct ufs_sb_private_info * uspi,
struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
{
switch (uspi->s_fpb) {
@@ -498,8 +494,7 @@ static inline void _ubh_clrblock_(struct ufs_sb_private_info * uspi,
}
}
-#define ubh_setblock(ubh,begin,block) _ubh_setblock_(uspi,ubh,begin,block)
-static inline void _ubh_setblock_(struct ufs_sb_private_info * uspi,
+static inline void ubh_setblock(struct ufs_sb_private_info * uspi,
struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
{
switch (uspi->s_fpb) {
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 07/12] ufs: untangle ubh_...block...(), part 2
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
` (4 preceding siblings ...)
2023-12-13 3:18 ` [PATCH 06/12] ufs: untangle ubh_...block...() macros, part 1 Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 08/12] ufs: untangle ubh_...block...(), part 3 Al Viro
` (4 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
pass cylinder group descriptor instead of its buffer head (ubh,
always UCPI_UBH(ucpi)) and its ->c_freeoff.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/balloc.c | 10 +++++-----
fs/ufs/util.h | 16 +++++++++++-----
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index e412ddcfda03..d76c04fbd4fa 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -95,7 +95,7 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
* Trying to reassemble free fragments into block
*/
blkno = ufs_fragstoblks (bbase);
- if (ubh_isblockset(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
+ if (ubh_isblockset(uspi, ucpi, blkno)) {
fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
uspi->cs_total.cs_nffree -= uspi->s_fpb;
fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
@@ -182,10 +182,10 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
for (i = bit; i < end_bit; i += uspi->s_fpb) {
blkno = ufs_fragstoblks(i);
- if (ubh_isblockset(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
+ if (ubh_isblockset(uspi, ucpi, blkno)) {
ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
}
- ubh_setblock(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
+ ubh_setblock(uspi, ucpi, blkno);
inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, 1);
@@ -716,7 +716,7 @@ static u64 ufs_alloccg_block(struct inode *inode,
/*
* If the requested block is available, use it.
*/
- if (ubh_isblockset(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
+ if (ubh_isblockset(uspi, ucpi, ufs_fragstoblks(goal))) {
result = goal;
goto gotit;
}
@@ -730,7 +730,7 @@ static u64 ufs_alloccg_block(struct inode *inode,
if (!try_add_frags(inode, uspi->s_fpb))
return 0;
blkno = ufs_fragstoblks(result);
- ubh_clrblock(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
+ ubh_clrblock(uspi, ucpi, blkno);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, -1);
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index dc3240f0ddea..89c890b5c54d 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -455,9 +455,11 @@ static inline unsigned _ubh_find_last_zero_bit_(
return (base << uspi->s_bpfshift) + pos - begin;
}
-static inline int ubh_isblockset(struct ufs_sb_private_info * uspi,
- struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
+static inline int ubh_isblockset(struct ufs_sb_private_info *uspi,
+ struct ufs_cg_private_info *ucpi, unsigned block)
{
+ struct ufs_buffer_head *ubh = UCPI_UBH(ucpi);
+ unsigned begin = ucpi->c_freeoff;
u8 mask;
switch (uspi->s_fpb) {
case 8:
@@ -475,9 +477,11 @@ static inline int ubh_isblockset(struct ufs_sb_private_info * uspi,
return 0;
}
-static inline void ubh_clrblock(struct ufs_sb_private_info * uspi,
- struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
+static inline void ubh_clrblock(struct ufs_sb_private_info *uspi,
+ struct ufs_cg_private_info *ucpi, unsigned block)
{
+ struct ufs_buffer_head *ubh = UCPI_UBH(ucpi);
+ unsigned begin = ucpi->c_freeoff;
switch (uspi->s_fpb) {
case 8:
*ubh_get_addr (ubh, begin + block) = 0x00;
@@ -495,8 +499,10 @@ static inline void ubh_clrblock(struct ufs_sb_private_info * uspi,
}
static inline void ubh_setblock(struct ufs_sb_private_info * uspi,
- struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
+ struct ufs_cg_private_info *ucpi, unsigned block)
{
+ struct ufs_buffer_head *ubh = UCPI_UBH(ucpi);
+ unsigned begin = ucpi->c_freeoff;
switch (uspi->s_fpb) {
case 8:
*ubh_get_addr(ubh, begin + block) = 0xff;
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 08/12] ufs: untangle ubh_...block...(), part 3
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
` (5 preceding siblings ...)
2023-12-13 3:18 ` [PATCH 07/12] ufs: untangle ubh_...block...(), part 2 Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 09/12] ufs_clusteracct(): switch to passing fragment number Al Viro
` (3 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
Pass fragment number instead of a block one. It's available in all
callers and it makes the logics inside those helpers much simpler.
The bitmap they operate upon is with bit per fragment, block being
an aligned group of 1, 2, 4 or 8 adjacent fragments. We still
need a switch by the number of fragments in block (== number of
bits to check/set/clear), but finding the byte we need to work
with becomes uniform and that makes the things easier to follow.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/balloc.c | 10 +++++-----
fs/ufs/util.h | 45 ++++++++++++++++++++++++---------------------
2 files changed, 29 insertions(+), 26 deletions(-)
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index d76c04fbd4fa..7694666fac18 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -95,7 +95,7 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
* Trying to reassemble free fragments into block
*/
blkno = ufs_fragstoblks (bbase);
- if (ubh_isblockset(uspi, ucpi, blkno)) {
+ if (ubh_isblockset(uspi, ucpi, bbase)) {
fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
uspi->cs_total.cs_nffree -= uspi->s_fpb;
fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
@@ -182,10 +182,10 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
for (i = bit; i < end_bit; i += uspi->s_fpb) {
blkno = ufs_fragstoblks(i);
- if (ubh_isblockset(uspi, ucpi, blkno)) {
+ if (ubh_isblockset(uspi, ucpi, i)) {
ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
}
- ubh_setblock(uspi, ucpi, blkno);
+ ubh_setblock(uspi, ucpi, i);
inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, 1);
@@ -716,7 +716,7 @@ static u64 ufs_alloccg_block(struct inode *inode,
/*
* If the requested block is available, use it.
*/
- if (ubh_isblockset(uspi, ucpi, ufs_fragstoblks(goal))) {
+ if (ubh_isblockset(uspi, ucpi, goal)) {
result = goal;
goto gotit;
}
@@ -730,7 +730,7 @@ static u64 ufs_alloccg_block(struct inode *inode,
if (!try_add_frags(inode, uspi->s_fpb))
return 0;
blkno = ufs_fragstoblks(result);
- ubh_clrblock(uspi, ucpi, blkno);
+ ubh_clrblock(uspi, ucpi, result);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, -1);
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 89c890b5c54d..6fff3da93a66 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -456,65 +456,68 @@ static inline unsigned _ubh_find_last_zero_bit_(
}
static inline int ubh_isblockset(struct ufs_sb_private_info *uspi,
- struct ufs_cg_private_info *ucpi, unsigned block)
+ struct ufs_cg_private_info *ucpi, unsigned int frag)
{
struct ufs_buffer_head *ubh = UCPI_UBH(ucpi);
- unsigned begin = ucpi->c_freeoff;
+ u8 *p = ubh_get_addr(ubh, ucpi->c_freeoff + (frag >> 3));
u8 mask;
+
switch (uspi->s_fpb) {
case 8:
- return (*ubh_get_addr (ubh, begin + block) == 0xff);
+ return *p == 0xff;
case 4:
- mask = 0x0f << ((block & 0x01) << 2);
- return (*ubh_get_addr (ubh, begin + (block >> 1)) & mask) == mask;
+ mask = 0x0f << (frag & 4);
+ return (*p & mask) == mask;
case 2:
- mask = 0x03 << ((block & 0x03) << 1);
- return (*ubh_get_addr (ubh, begin + (block >> 2)) & mask) == mask;
+ mask = 0x03 << (frag & 6);
+ return (*p & mask) == mask;
case 1:
- mask = 0x01 << (block & 0x07);
- return (*ubh_get_addr (ubh, begin + (block >> 3)) & mask) == mask;
+ mask = 0x01 << (frag & 7);
+ return (*p & mask) == mask;
}
return 0;
}
static inline void ubh_clrblock(struct ufs_sb_private_info *uspi,
- struct ufs_cg_private_info *ucpi, unsigned block)
+ struct ufs_cg_private_info *ucpi, unsigned int frag)
{
struct ufs_buffer_head *ubh = UCPI_UBH(ucpi);
- unsigned begin = ucpi->c_freeoff;
+ u8 *p = ubh_get_addr(ubh, ucpi->c_freeoff + (frag >> 3));
+
switch (uspi->s_fpb) {
case 8:
- *ubh_get_addr (ubh, begin + block) = 0x00;
+ *p = 0x00;
return;
case 4:
- *ubh_get_addr (ubh, begin + (block >> 1)) &= ~(0x0f << ((block & 0x01) << 2));
+ *p &= ~(0x0f << (frag & 4));
return;
case 2:
- *ubh_get_addr (ubh, begin + (block >> 2)) &= ~(0x03 << ((block & 0x03) << 1));
+ *p &= ~(0x03 << (frag & 6));
return;
case 1:
- *ubh_get_addr (ubh, begin + (block >> 3)) &= ~(0x01 << ((block & 0x07)));
+ *p &= ~(0x01 << (frag & 7));
return;
}
}
static inline void ubh_setblock(struct ufs_sb_private_info * uspi,
- struct ufs_cg_private_info *ucpi, unsigned block)
+ struct ufs_cg_private_info *ucpi, unsigned int frag)
{
struct ufs_buffer_head *ubh = UCPI_UBH(ucpi);
- unsigned begin = ucpi->c_freeoff;
+ u8 *p = ubh_get_addr(ubh, ucpi->c_freeoff + (frag >> 3));
+
switch (uspi->s_fpb) {
case 8:
- *ubh_get_addr(ubh, begin + block) = 0xff;
+ *p = 0xff;
return;
case 4:
- *ubh_get_addr(ubh, begin + (block >> 1)) |= (0x0f << ((block & 0x01) << 2));
+ *p |= 0x0f << (frag & 4);
return;
case 2:
- *ubh_get_addr(ubh, begin + (block >> 2)) |= (0x03 << ((block & 0x03) << 1));
+ *p |= 0x03 << (frag & 6);
return;
case 1:
- *ubh_get_addr(ubh, begin + (block >> 3)) |= (0x01 << ((block & 0x07)));
+ *p |= 0x01 << (frag & 7);
return;
}
}
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 09/12] ufs_clusteracct(): switch to passing fragment number
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
` (6 preceding siblings ...)
2023-12-13 3:18 ` [PATCH 08/12] ufs: untangle ubh_...block...(), part 3 Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 10/12] ufs_inode_getfrag(): remove junk comment Al Viro
` (2 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/balloc.c | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index 7694666fac18..1793ce48df0a 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -43,7 +43,6 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
struct ufs_cg_private_info * ucpi;
struct ufs_cylinder_group * ucg;
unsigned cgno, bit, end_bit, bbase, blkmap, i;
- u64 blkno;
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -94,13 +93,12 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
/*
* Trying to reassemble free fragments into block
*/
- blkno = ufs_fragstoblks (bbase);
if (ubh_isblockset(uspi, ucpi, bbase)) {
fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
uspi->cs_total.cs_nffree -= uspi->s_fpb;
fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
- ufs_clusteracct (sb, ucpi, blkno, 1);
+ ufs_clusteracct(sb, ucpi, bbase, 1);
fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
uspi->cs_total.cs_nbfree++;
fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
@@ -139,7 +137,6 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
struct ufs_cg_private_info * ucpi;
struct ufs_cylinder_group * ucg;
unsigned overflow, cgno, bit, end_bit, i;
- u64 blkno;
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -181,14 +178,13 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
}
for (i = bit; i < end_bit; i += uspi->s_fpb) {
- blkno = ufs_fragstoblks(i);
if (ubh_isblockset(uspi, ucpi, i)) {
ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
}
ubh_setblock(uspi, ucpi, i);
inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
- ufs_clusteracct (sb, ucpi, blkno, 1);
+ ufs_clusteracct(sb, ucpi, i, 1);
fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
uspi->cs_total.cs_nbfree++;
@@ -698,7 +694,7 @@ static u64 ufs_alloccg_block(struct inode *inode,
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct ufs_cylinder_group * ucg;
- u64 result, blkno;
+ u64 result;
UFSD("ENTER, goal %llu\n", (unsigned long long)goal);
@@ -729,10 +725,9 @@ static u64 ufs_alloccg_block(struct inode *inode,
gotit:
if (!try_add_frags(inode, uspi->s_fpb))
return 0;
- blkno = ufs_fragstoblks(result);
ubh_clrblock(uspi, ucpi, result);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
- ufs_clusteracct (sb, ucpi, blkno, -1);
+ ufs_clusteracct(sb, ucpi, result, -1);
fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
uspi->cs_total.cs_nbfree--;
@@ -863,12 +858,12 @@ static u64 ufs_bitmap_search(struct super_block *sb,
}
static void ufs_clusteracct(struct super_block * sb,
- struct ufs_cg_private_info * ucpi, unsigned blkno, int cnt)
+ struct ufs_cg_private_info * ucpi, unsigned frag, int cnt)
{
- struct ufs_sb_private_info * uspi;
+ struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
int i, start, end, forw, back;
+ unsigned blkno = ufs_fragstoblks(frag);
- uspi = UFS_SB(sb)->s_uspi;
if (uspi->s_contigsumsize <= 0)
return;
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 10/12] ufs_inode_getfrag(): remove junk comment
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
` (7 preceding siblings ...)
2023-12-13 3:18 ` [PATCH 09/12] ufs_clusteracct(): switch to passing fragment number Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 11/12] ufs: get rid of ubh_{ubhcpymem,memcpyubh}() Al Viro
2023-12-13 3:18 ` [PATCH 12/12] clean ufs_trunc_direct() up a bit Al Viro
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
It used to be a stubbed out beginning of ufs2 support, which had
been implemented differently quite a while ago. Remove the
commented-out (pseudo-)code.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/inode.c | 20 --------------------
1 file changed, 20 deletions(-)
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index ebce93b08281..e1c736409af8 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -263,11 +263,6 @@ ufs_inode_getfrag(struct inode *inode, unsigned index,
unsigned nfrags = uspi->s_fpb;
void *p;
- /* TODO : to be done for write support
- if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
- goto ufs2;
- */
-
p = ufs_get_direct_data_ptr(uspi, ufsi, index);
tmp = ufs_data_ptr_to_cpu(sb, p);
if (tmp)
@@ -302,21 +297,6 @@ ufs_inode_getfrag(struct inode *inode, unsigned index,
mark_inode_dirty(inode);
out:
return tmp + uspi->s_sbbase;
-
- /* This part : To be implemented ....
- Required only for writing, not required for READ-ONLY.
-ufs2:
-
- u2_block = ufs_fragstoblks(fragment);
- u2_blockoff = ufs_fragnum(fragment);
- p = ufsi->i_u1.u2_i_data + block;
- goal = 0;
-
-repeat2:
- tmp = fs32_to_cpu(sb, *p);
- lastfrag = ufsi->i_lastfrag;
-
- */
}
/**
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 11/12] ufs: get rid of ubh_{ubhcpymem,memcpyubh}()
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
` (8 preceding siblings ...)
2023-12-13 3:18 ` [PATCH 10/12] ufs_inode_getfrag(): remove junk comment Al Viro
@ 2023-12-13 3:18 ` Al Viro
2023-12-13 3:18 ` [PATCH 12/12] clean ufs_trunc_direct() up a bit Al Viro
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
used only in ufs_read_cylinder_structures()/ufs_put_super_internal()
and there we can just as well avoid bothering with ufs_buffer_head
and just deal with it fragment-by-fragment.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/super.c | 45 +++++++++++++++++----------------------------
fs/ufs/util.c | 46 ----------------------------------------------
fs/ufs/util.h | 5 -----
3 files changed, 17 insertions(+), 79 deletions(-)
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index a480810cd4e3..ccdfd4cb2682 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -505,7 +505,6 @@ static int ufs_read_cylinder_structures(struct super_block *sb)
{
struct ufs_sb_info *sbi = UFS_SB(sb);
struct ufs_sb_private_info *uspi = sbi->s_uspi;
- struct ufs_buffer_head * ubh;
unsigned char * base, * space;
unsigned size, blks, i;
@@ -521,21 +520,13 @@ static int ufs_read_cylinder_structures(struct super_block *sb)
if (!base)
goto failed;
sbi->s_csp = (struct ufs_csum *)space;
- for (i = 0; i < blks; i += uspi->s_fpb) {
- size = uspi->s_bsize;
- if (i + uspi->s_fpb > blks)
- size = (blks - i) * uspi->s_fsize;
-
- ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
-
- if (!ubh)
+ for (i = 0; i < blks; i++) {
+ struct buffer_head *bh = sb_bread(sb, uspi->s_csaddr + i);
+ if (!bh)
goto failed;
-
- ubh_ubhcpymem (space, ubh, size);
-
- space += size;
- ubh_brelse (ubh);
- ubh = NULL;
+ memcpy(space, bh->b_data, uspi->s_fsize);
+ space += uspi->s_fsize;
+ brelse (bh);
}
/*
@@ -645,7 +636,6 @@ static void ufs_put_super_internal(struct super_block *sb)
{
struct ufs_sb_info *sbi = UFS_SB(sb);
struct ufs_sb_private_info *uspi = sbi->s_uspi;
- struct ufs_buffer_head * ubh;
unsigned char * base, * space;
unsigned blks, size, i;
@@ -656,18 +646,17 @@ static void ufs_put_super_internal(struct super_block *sb)
size = uspi->s_cssize;
blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
base = space = (char*) sbi->s_csp;
- for (i = 0; i < blks; i += uspi->s_fpb) {
- size = uspi->s_bsize;
- if (i + uspi->s_fpb > blks)
- size = (blks - i) * uspi->s_fsize;
-
- ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
-
- ubh_memcpyubh (ubh, space, size);
- space += size;
- ubh_mark_buffer_uptodate (ubh, 1);
- ubh_mark_buffer_dirty (ubh);
- ubh_brelse (ubh);
+ for (i = 0; i < blks; i++, space += uspi->s_fsize) {
+ struct buffer_head *bh = sb_bread(sb, uspi->s_csaddr + i);
+
+ if (unlikely(!bh)) { // better than an oops...
+ ufs_panic(sb, __func__,
+ "can't write part of cylinder group summary");
+ continue;
+ }
+ memcpy(bh->b_data, space, uspi->s_fsize);
+ mark_buffer_dirty(bh);
+ brelse(bh);
}
for (i = 0; i < sbi->s_cg_loaded; i++) {
ufs_put_cylinder (sb, i);
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 13ba34e6d64f..535c7ee80a10 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -99,20 +99,6 @@ void ubh_mark_buffer_dirty (struct ufs_buffer_head * ubh)
mark_buffer_dirty (ubh->bh[i]);
}
-void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag)
-{
- unsigned i;
- if (!ubh)
- return;
- if (flag) {
- for ( i = 0; i < ubh->count; i++ )
- set_buffer_uptodate (ubh->bh[i]);
- } else {
- for ( i = 0; i < ubh->count; i++ )
- clear_buffer_uptodate (ubh->bh[i]);
- }
-}
-
void ubh_sync_block(struct ufs_buffer_head *ubh)
{
if (ubh) {
@@ -146,38 +132,6 @@ int ubh_buffer_dirty (struct ufs_buffer_head * ubh)
return result;
}
-void _ubh_ubhcpymem_(struct ufs_sb_private_info * uspi,
- unsigned char * mem, struct ufs_buffer_head * ubh, unsigned size)
-{
- unsigned len, bhno;
- if (size > (ubh->count << uspi->s_fshift))
- size = ubh->count << uspi->s_fshift;
- bhno = 0;
- while (size) {
- len = min_t(unsigned int, size, uspi->s_fsize);
- memcpy (mem, ubh->bh[bhno]->b_data, len);
- mem += uspi->s_fsize;
- size -= len;
- bhno++;
- }
-}
-
-void _ubh_memcpyubh_(struct ufs_sb_private_info * uspi,
- struct ufs_buffer_head * ubh, unsigned char * mem, unsigned size)
-{
- unsigned len, bhno;
- if (size > (ubh->count << uspi->s_fshift))
- size = ubh->count << uspi->s_fshift;
- bhno = 0;
- while (size) {
- len = min_t(unsigned int, size, uspi->s_fsize);
- memcpy (ubh->bh[bhno]->b_data, mem, len);
- mem += uspi->s_fsize;
- size -= len;
- bhno++;
- }
-}
-
dev_t
ufs_get_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi)
{
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 6fff3da93a66..eb6943fa7fa4 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -263,14 +263,9 @@ extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, str
extern void ubh_brelse (struct ufs_buffer_head *);
extern void ubh_brelse_uspi (struct ufs_sb_private_info *);
extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *);
-extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int);
extern void ubh_sync_block(struct ufs_buffer_head *);
extern void ubh_bforget (struct ufs_buffer_head *);
extern int ubh_buffer_dirty (struct ufs_buffer_head *);
-#define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size)
-extern void _ubh_ubhcpymem_(struct ufs_sb_private_info *, unsigned char *, struct ufs_buffer_head *, unsigned);
-#define ubh_memcpyubh(ubh,mem,size) _ubh_memcpyubh_(uspi,ubh,mem,size)
-extern void _ubh_memcpyubh_(struct ufs_sb_private_info *, struct ufs_buffer_head *, unsigned char *, unsigned);
/* This functions works with cache pages*/
struct folio *ufs_get_locked_folio(struct address_space *mapping, pgoff_t index);
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 12/12] clean ufs_trunc_direct() up a bit...
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
` (9 preceding siblings ...)
2023-12-13 3:18 ` [PATCH 11/12] ufs: get rid of ubh_{ubhcpymem,memcpyubh}() Al Viro
@ 2023-12-13 3:18 ` Al Viro
10 siblings, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 3:18 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco
For short files (== no indirect blocks needed) UFS allows the last
block to be a partial one. That creates some complications for
truncation down to "short file" lengths. ufs_trunc_direct() is
called when we'd already made sure that new EOF is not in a hole;
nothing needs to be done if we are extending the file and in
case we are shrinking the file it needs to
* shrink or free the old final block.
* free all full direct blocks between the new and old EOF.
* possibly shrink the new final block.
The logics is needlessly complicated by trying to keep all cases
handled by the same sequence of operations.
if not shrinking
nothing to do
else if number of full blocks unchanged
free the tail of possibly partial last block
else
free the tail of (full) new last block
free all present (full) blocks in between
free the (possibly partial) old last block
is easier to follow than the result of trying to unify these
cases.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/inode.c | 124 ++++++++++++++++++++++++-------------------------
1 file changed, 60 insertions(+), 64 deletions(-)
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index e1c736409af8..c573f444afd4 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -875,91 +875,87 @@ static inline void free_data(struct to_free *ctx, u64 from, unsigned count)
#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)
+/*
+ * used only for truncation down to direct blocks.
+ */
static void ufs_trunc_direct(struct inode *inode)
{
struct ufs_inode_info *ufsi = UFS_I(inode);
- struct super_block * sb;
- struct ufs_sb_private_info * uspi;
+ struct super_block *sb = inode->i_sb;
+ struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
void *p;
- u64 frag1, frag2, frag3, frag4, block1, block2;
+ u64 frag1, frag4, block1, block2;
+ unsigned old_partial, new_partial, old_blocks, new_blocks;
struct to_free ctx = {.inode = inode};
unsigned i, tmp;
UFSD("ENTER: ino %lu\n", inode->i_ino);
- sb = inode->i_sb;
- uspi = UFS_SB(sb)->s_uspi;
-
frag1 = DIRECT_FRAGMENT;
+ // frag1 = first fragment past the new EOF
frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag);
- frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1);
- frag3 = frag4 & ~uspi->s_fpbmask;
- block1 = block2 = 0;
- if (frag2 > frag3) {
- frag2 = frag4;
- frag3 = frag4 = 0;
- } else if (frag2 < frag3) {
- block1 = ufs_fragstoblks (frag2);
- block2 = ufs_fragstoblks (frag3);
- }
-
- UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu,"
- " frag3 %llu, frag4 %llu\n", inode->i_ino,
- (unsigned long long)frag1, (unsigned long long)frag2,
- (unsigned long long)block1, (unsigned long long)block2,
- (unsigned long long)frag3, (unsigned long long)frag4);
-
- if (frag1 >= frag2)
- goto next1;
+ // frag4 = first fragment past the old EOF or covered by indirects
- /*
- * Free first free fragments
- */
- p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1));
- tmp = ufs_data_ptr_to_cpu(sb, p);
- if (!tmp )
- ufs_panic (sb, "ufs_trunc_direct", "internal error");
- frag2 -= frag1;
- frag1 = ufs_fragnum (frag1);
+ if (frag1 >= frag4) // expanding - nothing to free
+ goto next3;
- ufs_free_fragments(inode, tmp + frag1, frag2);
+ old_partial = ufs_fragnum(frag4);
+ old_blocks = ufs_fragstoblks(frag4);
+ new_partial = ufs_fragnum(frag1);
+ new_blocks = ufs_fragstoblks(frag1);
-next1:
- /*
- * Free whole blocks
- */
- for (i = block1 ; i < block2; i++) {
- p = ufs_get_direct_data_ptr(uspi, ufsi, i);
+ if (old_blocks == new_blocks) {
+ p = ufs_get_direct_data_ptr(uspi, ufsi, new_blocks);
tmp = ufs_data_ptr_to_cpu(sb, p);
if (!tmp)
- continue;
- write_seqlock(&ufsi->meta_lock);
- ufs_data_ptr_clear(uspi, p);
- write_sequnlock(&ufsi->meta_lock);
+ ufs_panic (sb, "ufs_trunc_direct", "internal error");
+ if (!new_partial) {
+ write_seqlock(&ufsi->meta_lock);
+ ufs_data_ptr_clear(uspi, p);
+ write_sequnlock(&ufsi->meta_lock);
+ }
+ ufs_free_fragments(inode, tmp + new_partial,
+ old_partial - new_partial);
+ } else {
+ block1 = new_blocks;
+ block2 = old_partial ? old_blocks-1 : old_blocks;
+
+ if (new_partial) {
+ p = ufs_get_direct_data_ptr(uspi, ufsi, new_blocks);
+ tmp = ufs_data_ptr_to_cpu(sb, p);
+ if (!tmp)
+ ufs_panic (sb, "ufs_trunc_direct", "internal error");
+ ufs_free_fragments(inode, tmp + new_partial,
+ uspi->s_fpb - new_partial);
+ block1++;
+ }
+ for (i = block1 ; i < block2; i++) {
+ p = ufs_get_direct_data_ptr(uspi, ufsi, i);
+ tmp = ufs_data_ptr_to_cpu(sb, p);
+ if (!tmp)
+ continue;
+ write_seqlock(&ufsi->meta_lock);
+ ufs_data_ptr_clear(uspi, p);
+ write_sequnlock(&ufsi->meta_lock);
- free_data(&ctx, tmp, uspi->s_fpb);
- }
+ free_data(&ctx, tmp, uspi->s_fpb);
+ }
- free_data(&ctx, 0, 0);
+ free_data(&ctx, 0, 0);
- if (frag3 >= frag4)
- goto next3;
+ if (old_partial) {
+ p = ufs_get_direct_data_ptr(uspi, ufsi, old_blocks);
+ tmp = ufs_data_ptr_to_cpu(sb, p);
+ if (!tmp)
+ ufs_panic(sb, "ufs_truncate_direct", "internal error");
+ write_seqlock(&ufsi->meta_lock);
+ ufs_data_ptr_clear(uspi, p);
+ write_sequnlock(&ufsi->meta_lock);
- /*
- * Free last free fragments
- */
- p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3));
- tmp = ufs_data_ptr_to_cpu(sb, p);
- if (!tmp )
- ufs_panic(sb, "ufs_truncate_direct", "internal error");
- frag4 = ufs_fragnum (frag4);
- write_seqlock(&ufsi->meta_lock);
- ufs_data_ptr_clear(uspi, p);
- write_sequnlock(&ufsi->meta_lock);
-
- ufs_free_fragments (inode, tmp, frag4);
+ ufs_free_fragments(inode, tmp, old_partial);
+ }
+ }
next3:
-
UFSD("EXIT: ino %lu\n", inode->i_ino);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [patches][cft] ufs stuff
2023-12-13 3:16 [patches][cft] ufs stuff Al Viro
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
@ 2023-12-13 6:53 ` Al Viro
1 sibling, 0 replies; 14+ messages in thread
From: Al Viro @ 2023-12-13 6:53 UTC (permalink / raw)
To: linux-fsdevel; +Cc: Evgeniy Dushistov, Fabio M. De Francesco, Matthew Wilcox
On Wed, Dec 13, 2023 at 03:16:39AM +0000, Al Viro wrote:
> More old stuff, this time UFS one. Part of that is
> yet another kmap_local_page() conversion, part - assorted
> cleanups.
> It seems to survive local beating, but it needs
> more review and testing.
Sigh... That it does - especially since a bit more testing
has caught this (in mainline):
[PATCH] fix ufs_get_locked_folio() breakage
filemap_lock_folio() returns ERR_PTR(-ENOENT) if the thing is not
in cache - not NULL like find_lock_page() used to.
Fixes: 5fb7bd50b351 "ufs: add ufs_get_locked_folio and ufs_put_locked_folio"
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 535c7ee80a10..f0e906ab4ddd 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -199,7 +199,7 @@ struct folio *ufs_get_locked_folio(struct address_space *mapping,
{
struct inode *inode = mapping->host;
struct folio *folio = filemap_lock_folio(mapping, index);
- if (!folio) {
+ if (IS_ERR(folio)) {
folio = read_mapping_folio(mapping, index, NULL);
if (IS_ERR(folio)) {
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2023-12-13 6:53 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-13 3:16 [patches][cft] ufs stuff Al Viro
2023-12-13 3:18 ` [PATCH 01/12] fs/ufs: Use the offset_in_page() helper Al Viro
2023-12-13 3:18 ` [PATCH 02/12] fs/ufs: Change the signature of ufs_get_page() Al Viro
2023-12-13 3:18 ` [PATCH 03/12] fs/ufs: Use ufs_put_page() in ufs_rename() Al Viro
2023-12-13 3:18 ` [PATCH 04/12] fs/ufs: Replace kmap() with kmap_local_page() Al Viro
2023-12-13 3:18 ` [PATCH 05/12] ufs: fix handling of delete_entry and set_link failures Al Viro
2023-12-13 3:18 ` [PATCH 06/12] ufs: untangle ubh_...block...() macros, part 1 Al Viro
2023-12-13 3:18 ` [PATCH 07/12] ufs: untangle ubh_...block...(), part 2 Al Viro
2023-12-13 3:18 ` [PATCH 08/12] ufs: untangle ubh_...block...(), part 3 Al Viro
2023-12-13 3:18 ` [PATCH 09/12] ufs_clusteracct(): switch to passing fragment number Al Viro
2023-12-13 3:18 ` [PATCH 10/12] ufs_inode_getfrag(): remove junk comment Al Viro
2023-12-13 3:18 ` [PATCH 11/12] ufs: get rid of ubh_{ubhcpymem,memcpyubh}() Al Viro
2023-12-13 3:18 ` [PATCH 12/12] clean ufs_trunc_direct() up a bit Al Viro
2023-12-13 6:53 ` [patches][cft] ufs stuff Al Viro
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox