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"
25 #include "cifsproto.h"
28 * Key layout of CIFS server cache index object
30 struct cifs_server_key
{
32 uint16_t family
; /* address family */
33 __be16 port
; /* IP port */
36 struct in_addr ipv4_addr
;
37 struct in6_addr ipv6_addr
;
42 * Get a cookie for a server object keyed by {IPaddress,port,family} tuple
44 void cifs_fscache_get_client_cookie(struct TCP_Server_Info
*server
)
46 const struct sockaddr
*sa
= (struct sockaddr
*) &server
->dstaddr
;
47 const struct sockaddr_in
*addr
= (struct sockaddr_in
*) sa
;
48 const struct sockaddr_in6
*addr6
= (struct sockaddr_in6
*) sa
;
49 struct cifs_server_key key
;
50 uint16_t key_len
= sizeof(key
.hdr
);
52 memset(&key
, 0, sizeof(key
));
55 * Should not be a problem as sin_family/sin6_family overlays
58 key
.hdr
.family
= sa
->sa_family
;
59 switch (sa
->sa_family
) {
61 key
.hdr
.port
= addr
->sin_port
;
62 key
.ipv4_addr
= addr
->sin_addr
;
63 key_len
+= sizeof(key
.ipv4_addr
);
67 key
.hdr
.port
= addr6
->sin6_port
;
68 key
.ipv6_addr
= addr6
->sin6_addr
;
69 key_len
+= sizeof(key
.ipv6_addr
);
73 cifs_dbg(VFS
, "Unknown network family '%d'\n", sa
->sa_family
);
74 server
->fscache
= NULL
;
79 fscache_acquire_cookie(cifs_fscache_netfs
.primary_index
,
80 &cifs_fscache_server_index_def
,
84 cifs_dbg(FYI
, "%s: (0x%p/0x%p)\n",
85 __func__
, server
, server
->fscache
);
88 void cifs_fscache_release_client_cookie(struct TCP_Server_Info
*server
)
90 cifs_dbg(FYI
, "%s: (0x%p/0x%p)\n",
91 __func__
, server
, server
->fscache
);
92 fscache_relinquish_cookie(server
->fscache
, NULL
, false);
93 server
->fscache
= NULL
;
96 void cifs_fscache_get_super_cookie(struct cifs_tcon
*tcon
)
98 struct TCP_Server_Info
*server
= tcon
->ses
->server
;
100 struct cifs_fscache_super_auxdata auxdata
;
102 sharename
= extract_sharename(tcon
->treeName
);
103 if (IS_ERR(sharename
)) {
104 cifs_dbg(FYI
, "%s: couldn't extract sharename\n", __func__
);
105 tcon
->fscache
= NULL
;
109 memset(&auxdata
, 0, sizeof(auxdata
));
110 auxdata
.resource_id
= tcon
->resource_id
;
111 auxdata
.vol_create_time
= tcon
->vol_create_time
;
112 auxdata
.vol_serial_number
= tcon
->vol_serial_number
;
115 fscache_acquire_cookie(server
->fscache
,
116 &cifs_fscache_super_index_def
,
117 sharename
, strlen(sharename
),
118 &auxdata
, sizeof(auxdata
),
121 cifs_dbg(FYI
, "%s: (0x%p/0x%p)\n",
122 __func__
, server
->fscache
, tcon
->fscache
);
125 void cifs_fscache_release_super_cookie(struct cifs_tcon
*tcon
)
127 struct cifs_fscache_super_auxdata auxdata
;
129 memset(&auxdata
, 0, sizeof(auxdata
));
130 auxdata
.resource_id
= tcon
->resource_id
;
131 auxdata
.vol_create_time
= tcon
->vol_create_time
;
132 auxdata
.vol_serial_number
= tcon
->vol_serial_number
;
134 cifs_dbg(FYI
, "%s: (0x%p)\n", __func__
, tcon
->fscache
);
135 fscache_relinquish_cookie(tcon
->fscache
, &auxdata
, false);
136 tcon
->fscache
= NULL
;
139 static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo
*cifsi
,
140 struct cifs_tcon
*tcon
)
142 struct cifs_fscache_inode_auxdata auxdata
;
144 memset(&auxdata
, 0, sizeof(auxdata
));
145 auxdata
.eof
= cifsi
->server_eof
;
146 auxdata
.last_write_time_sec
= cifsi
->vfs_inode
.i_mtime
.tv_sec
;
147 auxdata
.last_change_time_sec
= cifsi
->vfs_inode
.i_ctime
.tv_sec
;
148 auxdata
.last_write_time_nsec
= cifsi
->vfs_inode
.i_mtime
.tv_nsec
;
149 auxdata
.last_change_time_nsec
= cifsi
->vfs_inode
.i_ctime
.tv_nsec
;
152 fscache_acquire_cookie(tcon
->fscache
,
153 &cifs_fscache_inode_object_def
,
154 &cifsi
->uniqueid
, sizeof(cifsi
->uniqueid
),
155 &auxdata
, sizeof(auxdata
),
156 cifsi
, cifsi
->vfs_inode
.i_size
, true);
159 static void cifs_fscache_enable_inode_cookie(struct inode
*inode
)
161 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
162 struct cifs_sb_info
*cifs_sb
= CIFS_SB(inode
->i_sb
);
163 struct cifs_tcon
*tcon
= cifs_sb_master_tcon(cifs_sb
);
168 if (!(cifs_sb
->mnt_cifs_flags
& CIFS_MOUNT_FSCACHE
))
171 cifs_fscache_acquire_inode_cookie(cifsi
, tcon
);
173 cifs_dbg(FYI
, "%s: got FH cookie (0x%p/0x%p)\n",
174 __func__
, tcon
->fscache
, cifsi
->fscache
);
177 void cifs_fscache_release_inode_cookie(struct inode
*inode
)
179 struct cifs_fscache_inode_auxdata auxdata
;
180 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
182 if (cifsi
->fscache
) {
183 memset(&auxdata
, 0, sizeof(auxdata
));
184 auxdata
.eof
= cifsi
->server_eof
;
185 auxdata
.last_write_time_sec
= cifsi
->vfs_inode
.i_mtime
.tv_sec
;
186 auxdata
.last_change_time_sec
= cifsi
->vfs_inode
.i_ctime
.tv_sec
;
187 auxdata
.last_write_time_nsec
= cifsi
->vfs_inode
.i_mtime
.tv_nsec
;
188 auxdata
.last_change_time_nsec
= cifsi
->vfs_inode
.i_ctime
.tv_nsec
;
190 cifs_dbg(FYI
, "%s: (0x%p)\n", __func__
, cifsi
->fscache
);
191 fscache_relinquish_cookie(cifsi
->fscache
, &auxdata
, false);
192 cifsi
->fscache
= NULL
;
196 static void cifs_fscache_disable_inode_cookie(struct inode
*inode
)
198 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
200 if (cifsi
->fscache
) {
201 cifs_dbg(FYI
, "%s: (0x%p)\n", __func__
, cifsi
->fscache
);
202 fscache_uncache_all_inode_pages(cifsi
->fscache
, inode
);
203 fscache_relinquish_cookie(cifsi
->fscache
, NULL
, true);
204 cifsi
->fscache
= NULL
;
208 void cifs_fscache_set_inode_cookie(struct inode
*inode
, struct file
*filp
)
210 if ((filp
->f_flags
& O_ACCMODE
) != O_RDONLY
)
211 cifs_fscache_disable_inode_cookie(inode
);
213 cifs_fscache_enable_inode_cookie(inode
);
216 void cifs_fscache_reset_inode_cookie(struct inode
*inode
)
218 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
219 struct cifs_sb_info
*cifs_sb
= CIFS_SB(inode
->i_sb
);
220 struct cifs_tcon
*tcon
= cifs_sb_master_tcon(cifs_sb
);
221 struct fscache_cookie
*old
= cifsi
->fscache
;
223 if (cifsi
->fscache
) {
224 /* retire the current fscache cache and get a new one */
225 fscache_relinquish_cookie(cifsi
->fscache
, NULL
, true);
227 cifs_fscache_acquire_inode_cookie(cifsi
, tcon
);
228 cifs_dbg(FYI
, "%s: new cookie 0x%p oldcookie 0x%p\n",
229 __func__
, cifsi
->fscache
, old
);
233 int cifs_fscache_release_page(struct page
*page
, gfp_t gfp
)
235 if (PageFsCache(page
)) {
236 struct inode
*inode
= page
->mapping
->host
;
237 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
239 cifs_dbg(FYI
, "%s: (0x%p/0x%p)\n",
240 __func__
, page
, cifsi
->fscache
);
241 if (!fscache_maybe_release_page(cifsi
->fscache
, page
, gfp
))
248 static void cifs_readpage_from_fscache_complete(struct page
*page
, void *ctx
,
251 cifs_dbg(FYI
, "%s: (0x%p/%d)\n", __func__
, page
, error
);
253 SetPageUptodate(page
);
258 * Retrieve a page from FS-Cache
260 int __cifs_readpage_from_fscache(struct inode
*inode
, struct page
*page
)
264 cifs_dbg(FYI
, "%s: (fsc:%p, p:%p, i:0x%p\n",
265 __func__
, CIFS_I(inode
)->fscache
, page
, inode
);
266 ret
= fscache_read_or_alloc_page(CIFS_I(inode
)->fscache
, page
,
267 cifs_readpage_from_fscache_complete
,
272 case 0: /* page found in fscache, read submitted */
273 cifs_dbg(FYI
, "%s: submitted\n", __func__
);
275 case -ENOBUFS
: /* page won't be cached */
276 case -ENODATA
: /* page not in cache */
277 cifs_dbg(FYI
, "%s: %d\n", __func__
, ret
);
281 cifs_dbg(VFS
, "unknown error ret = %d\n", ret
);
287 * Retrieve a set of pages from FS-Cache
289 int __cifs_readpages_from_fscache(struct inode
*inode
,
290 struct address_space
*mapping
,
291 struct list_head
*pages
,
296 cifs_dbg(FYI
, "%s: (0x%p/%u/0x%p)\n",
297 __func__
, CIFS_I(inode
)->fscache
, *nr_pages
, inode
);
298 ret
= fscache_read_or_alloc_pages(CIFS_I(inode
)->fscache
, mapping
,
300 cifs_readpage_from_fscache_complete
,
302 mapping_gfp_mask(mapping
));
304 case 0: /* read submitted to the cache for all pages */
305 cifs_dbg(FYI
, "%s: submitted\n", __func__
);
308 case -ENOBUFS
: /* some pages are not cached and can't be */
309 case -ENODATA
: /* some pages are not cached */
310 cifs_dbg(FYI
, "%s: no page\n", __func__
);
314 cifs_dbg(FYI
, "unknown error ret = %d\n", ret
);
320 void __cifs_readpage_to_fscache(struct inode
*inode
, struct page
*page
)
322 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
325 cifs_dbg(FYI
, "%s: (fsc: %p, p: %p, i: %p)\n",
326 __func__
, cifsi
->fscache
, page
, inode
);
327 ret
= fscache_write_page(cifsi
->fscache
, page
,
328 cifsi
->vfs_inode
.i_size
, GFP_KERNEL
);
330 fscache_uncache_page(cifsi
->fscache
, page
);
333 void __cifs_fscache_readpages_cancel(struct inode
*inode
, struct list_head
*pages
)
335 cifs_dbg(FYI
, "%s: (fsc: %p, i: %p)\n",
336 __func__
, CIFS_I(inode
)->fscache
, inode
);
337 fscache_readpages_cancel(CIFS_I(inode
)->fscache
, pages
);
340 void __cifs_fscache_invalidate_page(struct page
*page
, struct inode
*inode
)
342 struct cifsInodeInfo
*cifsi
= CIFS_I(inode
);
343 struct fscache_cookie
*cookie
= cifsi
->fscache
;
345 cifs_dbg(FYI
, "%s: (0x%p/0x%p)\n", __func__
, page
, cookie
);
346 fscache_wait_on_page_write(cookie
, page
);
347 fscache_uncache_page(cookie
, page
);