Blame view

fs/cifs/fscache.c 9.43 KB
488f1d2d6   Suresh Jayaraman   cifs: define serv...
1
2
3
4
  /*
   *   fs/cifs/fscache.c - CIFS filesystem cache interface
   *
   *   Copyright (c) 2010 Novell, Inc.
b81209de2   Suresh Jayaraman   cifs: enable fsca...
5
   *   Author(s): Suresh Jayaraman <sjayaraman@suse.de>
488f1d2d6   Suresh Jayaraman   cifs: define serv...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   *
   *   This library is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU Lesser General Public License as published
   *   by the Free Software Foundation; either version 2.1 of the License, or
   *   (at your option) any later version.
   *
   *   This library is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
   *   the GNU Lesser General Public License for more details.
   *
   *   You should have received a copy of the GNU Lesser General Public License
   *   along with this library; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  #include "fscache.h"
  #include "cifsglob.h"
  #include "cifs_debug.h"
9451a9a52   Suresh Jayaraman   cifs: define inod...
24
  #include "cifs_fs_sb.h"
488f1d2d6   Suresh Jayaraman   cifs: define serv...
25

402cb8dda   David Howells   fscache: Attach t...
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  /*
   * Key layout of CIFS server cache index object
   */
  struct cifs_server_key {
  	struct {
  		uint16_t	family;		/* address family */
  		__be16		port;		/* IP port */
  	} hdr;
  	union {
  		struct in_addr	ipv4_addr;
  		struct in6_addr	ipv6_addr;
  	};
  } __packed;
  
  /*
   * Get a cookie for a server object keyed by {IPaddress,port,family} tuple
   */
488f1d2d6   Suresh Jayaraman   cifs: define serv...
43
44
  void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server)
  {
402cb8dda   David Howells   fscache: Attach t...
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
  	const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr;
  	const struct sockaddr_in *addr = (struct sockaddr_in *) sa;
  	const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa;
  	struct cifs_server_key key;
  	uint16_t key_len = sizeof(key.hdr);
  
  	memset(&key, 0, sizeof(key));
  
  	/*
  	 * Should not be a problem as sin_family/sin6_family overlays
  	 * sa_family field
  	 */
  	key.hdr.family = sa->sa_family;
  	switch (sa->sa_family) {
  	case AF_INET:
  		key.hdr.port = addr->sin_port;
  		key.ipv4_addr = addr->sin_addr;
  		key_len += sizeof(key.ipv4_addr);
  		break;
  
  	case AF_INET6:
  		key.hdr.port = addr6->sin6_port;
  		key.ipv6_addr = addr6->sin6_addr;
  		key_len += sizeof(key.ipv6_addr);
  		break;
  
  	default:
  		cifs_dbg(VFS, "Unknown network family '%d'
  ", sa->sa_family);
  		server->fscache = NULL;
  		return;
  	}
488f1d2d6   Suresh Jayaraman   cifs: define serv...
77
78
  	server->fscache =
  		fscache_acquire_cookie(cifs_fscache_netfs.primary_index,
402cb8dda   David Howells   fscache: Attach t...
79
80
81
  				       &cifs_fscache_server_index_def,
  				       &key, key_len,
  				       NULL, 0,
ee1235a9a   David Howells   fscache: Pass obj...
82
  				       server, 0, true);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
83
84
85
  	cifs_dbg(FYI, "%s: (0x%p/0x%p)
  ",
  		 __func__, server, server->fscache);
488f1d2d6   Suresh Jayaraman   cifs: define serv...
86
87
88
89
  }
  
  void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server)
  {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
90
91
92
  	cifs_dbg(FYI, "%s: (0x%p/0x%p)
  ",
  		 __func__, server, server->fscache);
402cb8dda   David Howells   fscache: Attach t...
93
  	fscache_relinquish_cookie(server->fscache, NULL, false);
488f1d2d6   Suresh Jayaraman   cifs: define serv...
94
95
  	server->fscache = NULL;
  }
96daf2b09   Steve French   [CIFS] Rename thr...
96
  void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon)
d03382ce9   Suresh Jayaraman   cifs: define supe...
97
98
  {
  	struct TCP_Server_Info *server = tcon->ses->server;
402cb8dda   David Howells   fscache: Attach t...
99
100
101
102
103
104
105
106
107
  	char *sharename;
  
  	sharename = extract_sharename(tcon->treeName);
  	if (IS_ERR(sharename)) {
  		cifs_dbg(FYI, "%s: couldn't extract sharename
  ", __func__);
  		tcon->fscache = NULL;
  		return;
  	}
d03382ce9   Suresh Jayaraman   cifs: define supe...
108
109
110
  
  	tcon->fscache =
  		fscache_acquire_cookie(server->fscache,
402cb8dda   David Howells   fscache: Attach t...
111
112
113
  				       &cifs_fscache_super_index_def,
  				       sharename, strlen(sharename),
  				       &tcon->resource_id, sizeof(tcon->resource_id),
ee1235a9a   David Howells   fscache: Pass obj...
114
  				       tcon, 0, true);
402cb8dda   David Howells   fscache: Attach t...
115
  	kfree(sharename);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
116
117
118
  	cifs_dbg(FYI, "%s: (0x%p/0x%p)
  ",
  		 __func__, server->fscache, tcon->fscache);
d03382ce9   Suresh Jayaraman   cifs: define supe...
119
  }
96daf2b09   Steve French   [CIFS] Rename thr...
120
  void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon)
d03382ce9   Suresh Jayaraman   cifs: define supe...
121
  {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
122
123
  	cifs_dbg(FYI, "%s: (0x%p)
  ", __func__, tcon->fscache);
402cb8dda   David Howells   fscache: Attach t...
124
  	fscache_relinquish_cookie(tcon->fscache, &tcon->resource_id, false);
d03382ce9   Suresh Jayaraman   cifs: define supe...
125
126
  	tcon->fscache = NULL;
  }
9451a9a52   Suresh Jayaraman   cifs: define inod...
127

402cb8dda   David Howells   fscache: Attach t...
128
129
130
131
132
133
134
  static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo *cifsi,
  					      struct cifs_tcon *tcon)
  {
  	struct cifs_fscache_inode_auxdata auxdata;
  
  	memset(&auxdata, 0, sizeof(auxdata));
  	auxdata.eof = cifsi->server_eof;
cbedeadf9   Arnd Bergmann   cifs: use 64-bit ...
135
136
137
138
  	auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
  	auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
  	auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
  	auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
402cb8dda   David Howells   fscache: Attach t...
139
140
141
142
143
144
  
  	cifsi->fscache =
  		fscache_acquire_cookie(tcon->fscache,
  				       &cifs_fscache_inode_object_def,
  				       &cifsi->uniqueid, sizeof(cifsi->uniqueid),
  				       &auxdata, sizeof(auxdata),
ee1235a9a   David Howells   fscache: Pass obj...
145
  				       cifsi, cifsi->vfs_inode.i_size, true);
402cb8dda   David Howells   fscache: Attach t...
146
  }
9451a9a52   Suresh Jayaraman   cifs: define inod...
147
148
149
150
  static void cifs_fscache_enable_inode_cookie(struct inode *inode)
  {
  	struct cifsInodeInfo *cifsi = CIFS_I(inode);
  	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
96daf2b09   Steve French   [CIFS] Rename thr...
151
  	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
9451a9a52   Suresh Jayaraman   cifs: define inod...
152
153
154
  
  	if (cifsi->fscache)
  		return;
402cb8dda   David Howells   fscache: Attach t...
155
156
157
158
159
160
161
162
  	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE))
  		return;
  
  	cifs_fscache_acquire_inode_cookie(cifsi, tcon);
  
  	cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)
  ",
  		 __func__, tcon->fscache, cifsi->fscache);
9451a9a52   Suresh Jayaraman   cifs: define inod...
163
164
165
166
  }
  
  void cifs_fscache_release_inode_cookie(struct inode *inode)
  {
402cb8dda   David Howells   fscache: Attach t...
167
  	struct cifs_fscache_inode_auxdata auxdata;
9451a9a52   Suresh Jayaraman   cifs: define inod...
168
169
170
  	struct cifsInodeInfo *cifsi = CIFS_I(inode);
  
  	if (cifsi->fscache) {
402cb8dda   David Howells   fscache: Attach t...
171
172
  		memset(&auxdata, 0, sizeof(auxdata));
  		auxdata.eof = cifsi->server_eof;
cbedeadf9   Arnd Bergmann   cifs: use 64-bit ...
173
174
175
176
  		auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
  		auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
  		auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
  		auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
402cb8dda   David Howells   fscache: Attach t...
177

f96637be0   Joe Perches   [CIFS] cifs: Rena...
178
179
  		cifs_dbg(FYI, "%s: (0x%p)
  ", __func__, cifsi->fscache);
402cb8dda   David Howells   fscache: Attach t...
180
  		fscache_relinquish_cookie(cifsi->fscache, &auxdata, false);
9451a9a52   Suresh Jayaraman   cifs: define inod...
181
182
183
184
185
186
187
188
189
  		cifsi->fscache = NULL;
  	}
  }
  
  static void cifs_fscache_disable_inode_cookie(struct inode *inode)
  {
  	struct cifsInodeInfo *cifsi = CIFS_I(inode);
  
  	if (cifsi->fscache) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
190
191
  		cifs_dbg(FYI, "%s: (0x%p)
  ", __func__, cifsi->fscache);
c902ce1bf   David Howells   FS-Cache: Add a h...
192
  		fscache_uncache_all_inode_pages(cifsi->fscache, inode);
402cb8dda   David Howells   fscache: Attach t...
193
  		fscache_relinquish_cookie(cifsi->fscache, NULL, true);
9451a9a52   Suresh Jayaraman   cifs: define inod...
194
195
196
197
198
199
200
201
  		cifsi->fscache = NULL;
  	}
  }
  
  void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
  {
  	if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
  		cifs_fscache_disable_inode_cookie(inode);
b81209de2   Suresh Jayaraman   cifs: enable fsca...
202
  	else
9451a9a52   Suresh Jayaraman   cifs: define inod...
203
  		cifs_fscache_enable_inode_cookie(inode);
9451a9a52   Suresh Jayaraman   cifs: define inod...
204
205
206
207
208
209
  }
  
  void cifs_fscache_reset_inode_cookie(struct inode *inode)
  {
  	struct cifsInodeInfo *cifsi = CIFS_I(inode);
  	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
402cb8dda   David Howells   fscache: Attach t...
210
  	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
9451a9a52   Suresh Jayaraman   cifs: define inod...
211
212
213
214
  	struct fscache_cookie *old = cifsi->fscache;
  
  	if (cifsi->fscache) {
  		/* retire the current fscache cache and get a new one */
402cb8dda   David Howells   fscache: Attach t...
215
  		fscache_relinquish_cookie(cifsi->fscache, NULL, true);
9451a9a52   Suresh Jayaraman   cifs: define inod...
216

402cb8dda   David Howells   fscache: Attach t...
217
  		cifs_fscache_acquire_inode_cookie(cifsi, tcon);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
218
219
220
  		cifs_dbg(FYI, "%s: new cookie 0x%p oldcookie 0x%p
  ",
  			 __func__, cifsi->fscache, old);
9451a9a52   Suresh Jayaraman   cifs: define inod...
221
222
  	}
  }
85f2d6b44   Suresh Jayaraman   cifs: FS-Cache pa...
223
224
225
226
227
228
  
  int cifs_fscache_release_page(struct page *page, gfp_t gfp)
  {
  	if (PageFsCache(page)) {
  		struct inode *inode = page->mapping->host;
  		struct cifsInodeInfo *cifsi = CIFS_I(inode);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
229
230
231
  		cifs_dbg(FYI, "%s: (0x%p/0x%p)
  ",
  			 __func__, page, cifsi->fscache);
85f2d6b44   Suresh Jayaraman   cifs: FS-Cache pa...
232
233
234
235
236
237
  		if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
  			return 0;
  	}
  
  	return 1;
  }
56698236e   Suresh Jayaraman   cifs: read pages ...
238
239
240
  static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
  						int error)
  {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
241
242
  	cifs_dbg(FYI, "%s: (0x%p/%d)
  ", __func__, page, error);
56698236e   Suresh Jayaraman   cifs: read pages ...
243
244
245
246
247
248
249
250
251
252
253
  	if (!error)
  		SetPageUptodate(page);
  	unlock_page(page);
  }
  
  /*
   * Retrieve a page from FS-Cache
   */
  int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
  {
  	int ret;
f96637be0   Joe Perches   [CIFS] cifs: Rena...
254
255
256
  	cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p
  ",
  		 __func__, CIFS_I(inode)->fscache, page, inode);
56698236e   Suresh Jayaraman   cifs: read pages ...
257
258
259
260
261
262
263
  	ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
  					 cifs_readpage_from_fscache_complete,
  					 NULL,
  					 GFP_KERNEL);
  	switch (ret) {
  
  	case 0: /* page found in fscache, read submitted */
f96637be0   Joe Perches   [CIFS] cifs: Rena...
264
265
  		cifs_dbg(FYI, "%s: submitted
  ", __func__);
56698236e   Suresh Jayaraman   cifs: read pages ...
266
267
268
  		return ret;
  	case -ENOBUFS:	/* page won't be cached */
  	case -ENODATA:	/* page not in cache */
f96637be0   Joe Perches   [CIFS] cifs: Rena...
269
270
  		cifs_dbg(FYI, "%s: %d
  ", __func__, ret);
56698236e   Suresh Jayaraman   cifs: read pages ...
271
272
273
  		return 1;
  
  	default:
f96637be0   Joe Perches   [CIFS] cifs: Rena...
274
275
  		cifs_dbg(VFS, "unknown error ret = %d
  ", ret);
56698236e   Suresh Jayaraman   cifs: read pages ...
276
277
278
279
280
281
282
283
284
285
286
287
288
  	}
  	return ret;
  }
  
  /*
   * Retrieve a set of pages from FS-Cache
   */
  int __cifs_readpages_from_fscache(struct inode *inode,
  				struct address_space *mapping,
  				struct list_head *pages,
  				unsigned *nr_pages)
  {
  	int ret;
f96637be0   Joe Perches   [CIFS] cifs: Rena...
289
290
291
  	cifs_dbg(FYI, "%s: (0x%p/%u/0x%p)
  ",
  		 __func__, CIFS_I(inode)->fscache, *nr_pages, inode);
56698236e   Suresh Jayaraman   cifs: read pages ...
292
293
294
295
296
297
298
  	ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
  					  pages, nr_pages,
  					  cifs_readpage_from_fscache_complete,
  					  NULL,
  					  mapping_gfp_mask(mapping));
  	switch (ret) {
  	case 0:	/* read submitted to the cache for all pages */
f96637be0   Joe Perches   [CIFS] cifs: Rena...
299
300
  		cifs_dbg(FYI, "%s: submitted
  ", __func__);
56698236e   Suresh Jayaraman   cifs: read pages ...
301
302
303
304
  		return ret;
  
  	case -ENOBUFS:	/* some pages are not cached and can't be */
  	case -ENODATA:	/* some pages are not cached */
f96637be0   Joe Perches   [CIFS] cifs: Rena...
305
306
  		cifs_dbg(FYI, "%s: no page
  ", __func__);
56698236e   Suresh Jayaraman   cifs: read pages ...
307
308
309
  		return 1;
  
  	default:
f96637be0   Joe Perches   [CIFS] cifs: Rena...
310
311
  		cifs_dbg(FYI, "unknown error ret = %d
  ", ret);
56698236e   Suresh Jayaraman   cifs: read pages ...
312
313
314
315
  	}
  
  	return ret;
  }
9dc06558c   Suresh Jayaraman   cifs: store pages...
316
317
  void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
  {
ee1235a9a   David Howells   fscache: Pass obj...
318
  	struct cifsInodeInfo *cifsi = CIFS_I(inode);
9dc06558c   Suresh Jayaraman   cifs: store pages...
319
  	int ret;
f96637be0   Joe Perches   [CIFS] cifs: Rena...
320
321
  	cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)
  ",
ee1235a9a   David Howells   fscache: Pass obj...
322
323
324
  		 __func__, cifsi->fscache, page, inode);
  	ret = fscache_write_page(cifsi->fscache, page,
  				 cifsi->vfs_inode.i_size, GFP_KERNEL);
9dc06558c   Suresh Jayaraman   cifs: store pages...
325
  	if (ret != 0)
ee1235a9a   David Howells   fscache: Pass obj...
326
  		fscache_uncache_page(cifsi->fscache, page);
9dc06558c   Suresh Jayaraman   cifs: store pages...
327
  }
54afa9905   David Howells   CIFS: FS-Cache: U...
328
329
330
331
332
333
334
  void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages)
  {
  	cifs_dbg(FYI, "%s: (fsc: %p, i: %p)
  ",
  		 __func__, CIFS_I(inode)->fscache, inode);
  	fscache_readpages_cancel(CIFS_I(inode)->fscache, pages);
  }
85f2d6b44   Suresh Jayaraman   cifs: FS-Cache pa...
335
336
337
338
  void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
  {
  	struct cifsInodeInfo *cifsi = CIFS_I(inode);
  	struct fscache_cookie *cookie = cifsi->fscache;
f96637be0   Joe Perches   [CIFS] cifs: Rena...
339
340
  	cifs_dbg(FYI, "%s: (0x%p/0x%p)
  ", __func__, page, cookie);
85f2d6b44   Suresh Jayaraman   cifs: FS-Cache pa...
341
342
343
  	fscache_wait_on_page_write(cookie, page);
  	fscache_uncache_page(cookie, page);
  }