1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
// SPDX-License-Identifier: GPL-2.0-only
/* Miscellaneous routines.
*
* Copyright (C) 2023 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*/
#include <linux/swap.h>
#include "internal.h"
/**
* netfs_dirty_folio - Mark folio dirty and pin a cache object for writeback
* @mapping: The mapping the folio belongs to.
* @folio: The folio being dirtied.
*
* Set the dirty flag on a folio and pin an in-use cache object in memory so
* that writeback can later write to it. This is intended to be called from
* the filesystem's ->dirty_folio() method.
*
* Return: true if the dirty flag was set on the folio, false otherwise.
*/
bool netfs_dirty_folio(struct address_space *mapping, struct folio *folio)
{
struct inode *inode = mapping->host;
struct netfs_inode *ictx = netfs_inode(inode);
struct fscache_cookie *cookie = netfs_i_cookie(ictx);
bool need_use = false;
_enter("");
if (!filemap_dirty_folio(mapping, folio))
return false;
if (!fscache_cookie_valid(cookie))
return true;
if (!(inode->i_state & I_PINNING_NETFS_WB)) {
spin_lock(&inode->i_lock);
if (!(inode->i_state & I_PINNING_NETFS_WB)) {
inode->i_state |= I_PINNING_NETFS_WB;
need_use = true;
}
spin_unlock(&inode->i_lock);
if (need_use)
fscache_use_cookie(cookie, true);
}
return true;
}
EXPORT_SYMBOL(netfs_dirty_folio);
/**
* netfs_unpin_writeback - Unpin writeback resources
* @inode: The inode on which the cookie resides
* @wbc: The writeback control
*
* Unpin the writeback resources pinned by netfs_dirty_folio(). This is
* intended to be called as/by the netfs's ->write_inode() method.
*/
int netfs_unpin_writeback(struct inode *inode, struct writeback_control *wbc)
{
struct fscache_cookie *cookie = netfs_i_cookie(netfs_inode(inode));
if (wbc->unpinned_netfs_wb)
fscache_unuse_cookie(cookie, NULL, NULL);
return 0;
}
EXPORT_SYMBOL(netfs_unpin_writeback);
/**
* netfs_clear_inode_writeback - Clear writeback resources pinned by an inode
* @inode: The inode to clean up
* @aux: Auxiliary data to apply to the inode
*
* Clear any writeback resources held by an inode when the inode is evicted.
* This must be called before clear_inode() is called.
*/
void netfs_clear_inode_writeback(struct inode *inode, const void *aux)
{
struct fscache_cookie *cookie = netfs_i_cookie(netfs_inode(inode));
if (inode->i_state & I_PINNING_NETFS_WB) {
loff_t i_size = i_size_read(inode);
fscache_unuse_cookie(cookie, aux, &i_size);
}
}
EXPORT_SYMBOL(netfs_clear_inode_writeback);
/**
* netfs_invalidate_folio - Invalidate or partially invalidate a folio
* @folio: Folio proposed for release
* @offset: Offset of the invalidated region
* @length: Length of the invalidated region
*
* Invalidate part or all of a folio for a network filesystem. The folio will
* be removed afterwards if the invalidated region covers the entire folio.
*/
void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length)
{
_enter("{%lx},%zx,%zx", folio_index(folio), offset, length);
folio_wait_fscache(folio);
}
EXPORT_SYMBOL(netfs_invalidate_folio);
/**
* netfs_release_folio - Try to release a folio
* @folio: Folio proposed for release
* @gfp: Flags qualifying the release
*
* Request release of a folio and clean up its private state if it's not busy.
* Returns true if the folio can now be released, false if not
*/
bool netfs_release_folio(struct folio *folio, gfp_t gfp)
{
struct netfs_inode *ctx = netfs_inode(folio_inode(folio));
if (folio_test_private(folio))
return false;
if (folio_test_fscache(folio)) {
if (current_is_kswapd() || !(gfp & __GFP_FS))
return false;
folio_wait_fscache(folio);
}
fscache_note_page_release(netfs_i_cookie(ctx));
return true;
}
EXPORT_SYMBOL(netfs_release_folio);
|