2 * fs/cifs/fscache.c - CIFS filesystem cache interface
4 * Copyright (c) 2010 Novell, Inc.
5 * Author(s): Suresh Jayaraman <sjayaraman@suse.de>
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "cifs_debug.h"
24 #include "cifs_fs_sb.h"
27 * Key layout of CIFS server cache index object
29 struct cifs_server_key
{
31 uint16_t family
; /* address family */
32 __be16 port
; /* IP port */
35 struct in_addr ipv4_addr
;
36 struct in6_addr ipv6_addr
;
41 * Get a cookie for a server object keyed by {IPaddress,port,family} tuple
43 void cifs_fscache_get_client_cookie(struct TCP_Server_Info
*server
)
45 const struct sockaddr
*sa
= (struct sockaddr
*) &server
->dstaddr
;
46 const struct sockaddr_in
*addr
= (struct sockaddr_in
*) sa
;
47 const struct sockaddr_in6
*addr6
= (struct sockaddr_in6
*) sa
;
48 struct cifs_server_key key
;
49 uint16_t key_len
= sizeof(key
.hdr
);
51 memset(&key
, 0, sizeof(key
));
54 * Should not be a problem as sin_family/sin6_family overlays
57 key
.hdr
.family
= sa
->sa_family
;
58 switch (sa
->sa_family
) {
60 key
.hdr
.port
= addr
->sin_port
;
61 key
.ipv4_addr
= addr
->sin_addr
;
62 key_len
+= sizeof(key
.ipv4_addr
);
66 key
.hdr
.port
= addr6
->sin6_port
;
67 key
.ipv6_addr
= addr6
->sin6_addr
;
68 key_len
+= sizeof(key
.ipv6_addr
);
72 cifs_dbg(VFS
, "Unknown network family '%d'\n", sa
->sa_family
);
73 server
->fscache
= NULL
;
78 fscache_acquire_cookie(cifs_fscache_netfs
.primary_index
,
79 &cifs_fscache_server_index_def
,
83 cifs_dbg(FYI
, "%s: (0x%p/0x%p)\n",
84 __func__
, server
, server
->fscache
);
87 void cifs_fscache_release_client_cookie(struct TCP_Server_Info
*server
)
89 cifs_dbg(FYI
, "%s: (0x%p/0x%p)\n",
90 __func__
, server
, server
->fscache
);
91 fscache_relinquish_cookie(server
->fscache
, NULL
, false);
92 server
->fscache
= NULL
;
95 void cifs_fscache_get_super_cookie(struct cifs_tcon
*tcon
)
97 struct TCP_Server_Info
*server
= tcon
->ses
->server
;
100 sharename
= extract_sharename(tcon
->treeName
);
101 if (IS_ERR(sharename
)) {
102 cifs_dbg(FYI
, "%s: couldn't extract sharename\n", __func__
);
103 tcon
->fscache
= NULL
;
108 fscache_acquire_cookie(server
->fscache
,
109 &cifs_fscache_super_index_def
,
110 sharename
, strlen(sharename
),
111 &tcon
->resource_id
, sizeof(tcon
->resource_id
),
114 cifs_dbg(FYI
, "%s: (0x%p/0x%p)\n",
115 __func__
, server
->fscache
, tcon
->fscache
);
118 void cifs_fscache_release_super_cookie(struct cifs_tcon
*tcon
)
120 cifs_dbg(FYI
, "%s: (0x%p)\n", __func__
, tcon
->fscache
);
121 fscache_relinquish_cookie(tcon
->fscache
, &tcon
->resource_id
, false);
122 tcon
->fscache
= NULL
;
125 static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo
*cifsi
,
126 struct cifs_tcon
*tcon
)
128 struct cifs_fscache_inode_auxdata auxdata
;
130 memset(&auxdata
, 0, sizeof(auxdata
));
131 auxdata
.eof
= cifsi
->server_eof
;
132 auxdata
.last_write_time
= timespec64_to_timespec(cifsi
->vfs_inode
.i_mtime
);
133 auxdata
.last_change_time
= timespec64_to_timespec(cifsi
->vfs_inode
.i_ctime
);
136 fscache_acquire_cookie(tcon
->fscache
,
137 &cifs_fscache_inode_object_def
,
138 &cifsi
->uniqueid
, sizeof(cifsi
->uniqueid
),
139 &auxdata
, sizeof(auxdata
),
140 cifsi
, cifsi
->vfs_inode
.i_size
, true);
143 static void cifs_fscache_enable_inode_cookie(struct inode
*inode
)
145 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
146 struct cifs_sb_info
*cifs_sb
= CIFS_SB(inode
->i_sb
);
147 struct cifs_tcon
*tcon
= cifs_sb_master_tcon(cifs_sb
);
152 if (!(cifs_sb
->mnt_cifs_flags
& CIFS_MOUNT_FSCACHE
))
155 cifs_fscache_acquire_inode_cookie(cifsi
, tcon
);
157 cifs_dbg(FYI
, "%s: got FH cookie (0x%p/0x%p)\n",
158 __func__
, tcon
->fscache
, cifsi
->fscache
);
161 void cifs_fscache_release_inode_cookie(struct inode
*inode
)
163 struct cifs_fscache_inode_auxdata auxdata
;
164 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
166 if (cifsi
->fscache
) {
167 memset(&auxdata
, 0, sizeof(auxdata
));
168 auxdata
.eof
= cifsi
->server_eof
;
169 auxdata
.last_write_time
= timespec64_to_timespec(cifsi
->vfs_inode
.i_mtime
);
170 auxdata
.last_change_time
= timespec64_to_timespec(cifsi
->vfs_inode
.i_ctime
);
172 cifs_dbg(FYI
, "%s: (0x%p)\n", __func__
, cifsi
->fscache
);
173 fscache_relinquish_cookie(cifsi
->fscache
, &auxdata
, false);
174 cifsi
->fscache
= NULL
;
178 static void cifs_fscache_disable_inode_cookie(struct inode
*inode
)
180 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
182 if (cifsi
->fscache
) {
183 cifs_dbg(FYI
, "%s: (0x%p)\n", __func__
, cifsi
->fscache
);
184 fscache_uncache_all_inode_pages(cifsi
->fscache
, inode
);
185 fscache_relinquish_cookie(cifsi
->fscache
, NULL
, true);
186 cifsi
->fscache
= NULL
;
190 void cifs_fscache_set_inode_cookie(struct inode
*inode
, struct file
*filp
)
192 if ((filp
->f_flags
& O_ACCMODE
) != O_RDONLY
)
193 cifs_fscache_disable_inode_cookie(inode
);
195 cifs_fscache_enable_inode_cookie(inode
);
198 void cifs_fscache_reset_inode_cookie(struct inode
*inode
)
200 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
201 struct cifs_sb_info
*cifs_sb
= CIFS_SB(inode
->i_sb
);
202 struct cifs_tcon
*tcon
= cifs_sb_master_tcon(cifs_sb
);
203 struct fscache_cookie
*old
= cifsi
->fscache
;
205 if (cifsi
->fscache
) {
206 /* retire the current fscache cache and get a new one */
207 fscache_relinquish_cookie(cifsi
->fscache
, NULL
, true);
209 cifs_fscache_acquire_inode_cookie(cifsi
, tcon
);
210 cifs_dbg(FYI
, "%s: new cookie 0x%p oldcookie 0x%p\n",
211 __func__
, cifsi
->fscache
, old
);
215 int cifs_fscache_release_page(struct page
*page
, gfp_t gfp
)
217 if (PageFsCache(page
)) {
218 struct inode
*inode
= page
->mapping
->host
;
219 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
221 cifs_dbg(FYI
, "%s: (0x%p/0x%p)\n",
222 __func__
, page
, cifsi
->fscache
);
223 if (!fscache_maybe_release_page(cifsi
->fscache
, page
, gfp
))
230 static void cifs_readpage_from_fscache_complete(struct page
*page
, void *ctx
,
233 cifs_dbg(FYI
, "%s: (0x%p/%d)\n", __func__
, page
, error
);
235 SetPageUptodate(page
);
240 * Retrieve a page from FS-Cache
242 int __cifs_readpage_from_fscache(struct inode
*inode
, struct page
*page
)
246 cifs_dbg(FYI
, "%s: (fsc:%p, p:%p, i:0x%p\n",
247 __func__
, CIFS_I(inode
)->fscache
, page
, inode
);
248 ret
= fscache_read_or_alloc_page(CIFS_I(inode
)->fscache
, page
,
249 cifs_readpage_from_fscache_complete
,
254 case 0: /* page found in fscache, read submitted */
255 cifs_dbg(FYI
, "%s: submitted\n", __func__
);
257 case -ENOBUFS
: /* page won't be cached */
258 case -ENODATA
: /* page not in cache */
259 cifs_dbg(FYI
, "%s: %d\n", __func__
, ret
);
263 cifs_dbg(VFS
, "unknown error ret = %d\n", ret
);
269 * Retrieve a set of pages from FS-Cache
271 int __cifs_readpages_from_fscache(struct inode
*inode
,
272 struct address_space
*mapping
,
273 struct list_head
*pages
,
278 cifs_dbg(FYI
, "%s: (0x%p/%u/0x%p)\n",
279 __func__
, CIFS_I(inode
)->fscache
, *nr_pages
, inode
);
280 ret
= fscache_read_or_alloc_pages(CIFS_I(inode
)->fscache
, mapping
,
282 cifs_readpage_from_fscache_complete
,
284 mapping_gfp_mask(mapping
));
286 case 0: /* read submitted to the cache for all pages */
287 cifs_dbg(FYI
, "%s: submitted\n", __func__
);
290 case -ENOBUFS
: /* some pages are not cached and can't be */
291 case -ENODATA
: /* some pages are not cached */
292 cifs_dbg(FYI
, "%s: no page\n", __func__
);
296 cifs_dbg(FYI
, "unknown error ret = %d\n", ret
);
302 void __cifs_readpage_to_fscache(struct inode
*inode
, struct page
*page
)
304 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
307 cifs_dbg(FYI
, "%s: (fsc: %p, p: %p, i: %p)\n",
308 __func__
, cifsi
->fscache
, page
, inode
);
309 ret
= fscache_write_page(cifsi
->fscache
, page
,
310 cifsi
->vfs_inode
.i_size
, GFP_KERNEL
);
312 fscache_uncache_page(cifsi
->fscache
, page
);
315 void __cifs_fscache_readpages_cancel(struct inode
*inode
, struct list_head
*pages
)
317 cifs_dbg(FYI
, "%s: (fsc: %p, i: %p)\n",
318 __func__
, CIFS_I(inode
)->fscache
, inode
);
319 fscache_readpages_cancel(CIFS_I(inode
)->fscache
, pages
);
322 void __cifs_fscache_invalidate_page(struct page
*page
, struct inode
*inode
)
324 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
325 struct fscache_cookie
*cookie
= cifsi
->fscache
;
327 cifs_dbg(FYI
, "%s: (0x%p/0x%p)\n", __func__
, page
, cookie
);
328 fscache_wait_on_page_write(cookie
, page
);
329 fscache_uncache_page(cookie
, page
);