Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
543ef2eb
Commit
543ef2eb
authored
5 years ago
by
Kent Overstreet
Committed by
Kent Overstreet
1 year ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bcachefs: Handle partial pages in seek data/hole
Signed-off-by:
Kent Overstreet
<
kent.overstreet@linux.dev
>
parent
d1542e03
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
55 additions
and
30 deletions
+55
-30
fs/bcachefs/fs-io.c
fs/bcachefs/fs-io.c
+55
-30
No files found.
fs/bcachefs/fs-io.c
View file @
543ef2eb
...
...
@@ -2833,22 +2833,20 @@ long bch2_fallocate_dispatch(struct file *file, int mode,
/* fseek: */
static
bool
folio_is_data
(
struct
folio
*
folio
)
static
int
folio_data_offset
(
struct
folio
*
folio
,
unsigned
offset
)
{
struct
bch_page_state
*
s
=
bch2_page_state
(
&
folio
->
page
);
unsigned
i
;
if
(
!
s
)
return
false
;
for
(
i
=
0
;
i
<
PAGE_SECTORS
;
i
++
)
if
(
s
)
for
(
i
=
offset
>>
9
;
i
<
PAGE_SECTORS
;
i
++
)
if
(
s
->
s
[
i
].
state
>=
SECTOR_DIRTY
)
return
true
;
return
i
<<
9
;
return
false
;
return
-
1
;
}
static
loff_t
bch2_
next
_pagecache_data
(
struct
inode
*
vinode
,
static
loff_t
bch2_
seek
_pagecache_data
(
struct
inode
*
vinode
,
loff_t
start_offset
,
loff_t
end_offset
)
{
...
...
@@ -2857,6 +2855,8 @@ static loff_t bch2_next_pagecache_data(struct inode *vinode,
pgoff_t
end_index
=
end_offset
>>
PAGE_SHIFT
;
pgoff_t
index
=
start_index
;
unsigned
i
;
loff_t
ret
;
int
offset
;
folio_batch_init
(
&
fbatch
);
...
...
@@ -2866,14 +2866,17 @@ static loff_t bch2_next_pagecache_data(struct inode *vinode,
struct
folio
*
folio
=
fbatch
.
folios
[
i
];
folio_lock
(
folio
);
if
(
folio_is_data
(
folio
))
{
end_offset
=
min
(
end_offset
,
max
(
start_offset
,
((
loff_t
)
folio
->
index
)
<<
PAGE_SHIFT
));
offset
=
folio_data_offset
(
folio
,
folio
->
index
==
start_index
?
start_offset
&
(
PAGE_SIZE
-
1
)
:
0
);
if
(
offset
>=
0
)
{
ret
=
clamp
(((
loff_t
)
folio
->
index
<<
PAGE_SHIFT
)
+
offset
,
start_offset
,
end_offset
);
folio_unlock
(
folio
);
folio_batch_release
(
&
fbatch
);
return
end_offs
et
;
return
r
et
;
}
folio_unlock
(
folio
);
}
...
...
@@ -2916,7 +2919,7 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
return
ret
;
if
(
next_data
>
offset
)
next_data
=
bch2_
next
_pagecache_data
(
&
inode
->
v
,
next_data
=
bch2_
seek
_pagecache_data
(
&
inode
->
v
,
offset
,
next_data
);
if
(
next_data
>=
isize
)
...
...
@@ -2925,34 +2928,56 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
return
vfs_setpos
(
file
,
next_data
,
MAX_LFS_FILESIZE
);
}
static
bool
page_slot_is_data
(
struct
address_space
*
mapping
,
pgoff_t
index
)
static
int
__page_hole_offset
(
struct
page
*
page
,
unsigned
offset
)
{
struct
bch_page_state
*
s
=
bch2_page_state
(
page
);
unsigned
i
;
if
(
!
s
)
return
0
;
for
(
i
=
offset
>>
9
;
i
<
PAGE_SECTORS
;
i
++
)
if
(
s
->
s
[
i
].
state
<
SECTOR_DIRTY
)
return
i
<<
9
;
return
-
1
;
}
static
loff_t
page_hole_offset
(
struct
address_space
*
mapping
,
loff_t
offset
)
{
pgoff_t
index
=
offset
>>
PAGE_SHIFT
;
struct
page
*
page
;
bool
ret
;
int
pg_offset
;
loff_t
ret
=
-
1
;
page
=
find_lock_page
(
mapping
,
index
);
if
(
!
page
)
return
false
;
return
offset
;
pg_offset
=
__page_hole_offset
(
page
,
offset
&
(
PAGE_SIZE
-
1
));
if
(
pg_offset
>=
0
)
ret
=
((
loff_t
)
index
<<
PAGE_SHIFT
)
+
pg_offset
;
ret
=
folio_is_data
(
page_folio
(
page
));
unlock_page
(
page
);
return
ret
;
}
static
loff_t
bch2_
next
_pagecache_hole
(
struct
inode
*
vinode
,
static
loff_t
bch2_
seek
_pagecache_hole
(
struct
inode
*
vinode
,
loff_t
start_offset
,
loff_t
end_offset
)
{
struct
address_space
*
mapping
=
vinode
->
i_mapping
;
pgoff_t
index
;
loff_t
offset
=
start_offset
,
hole
;
while
(
offset
<
end_offset
)
{
hole
=
page_hole_offset
(
mapping
,
offset
);
if
(
hole
>=
0
&&
hole
<=
end_offset
)
return
max
(
start_offset
,
hole
);
for
(
index
=
start_offset
>>
PAGE_SHIFT
;
index
<
end_offset
>>
PAGE_SHIFT
;
index
++
)
if
(
!
page_slot_is_data
(
mapping
,
index
))
end_offset
=
max
(
start_offset
,
((
loff_t
)
index
)
<<
PAGE_SHIFT
);
offset
+=
PAGE_SIZE
;
offset
&=
PAGE_MASK
;
}
return
end_offset
;
}
...
...
@@ -2977,11 +3002,11 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
POS
(
inode
->
v
.
i_ino
,
offset
>>
9
),
BTREE_ITER_SLOTS
,
k
,
ret
)
{
if
(
k
.
k
->
p
.
inode
!=
inode
->
v
.
i_ino
)
{
next_hole
=
bch2_
next
_pagecache_hole
(
&
inode
->
v
,
next_hole
=
bch2_
seek
_pagecache_hole
(
&
inode
->
v
,
offset
,
MAX_LFS_FILESIZE
);
break
;
}
else
if
(
!
bkey_extent_is_data
(
k
.
k
))
{
next_hole
=
bch2_
next
_pagecache_hole
(
&
inode
->
v
,
next_hole
=
bch2_
seek
_pagecache_hole
(
&
inode
->
v
,
max
(
offset
,
bkey_start_offset
(
k
.
k
)
<<
9
),
k
.
k
->
p
.
offset
<<
9
);
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment