Merge branch 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[pandora-kernel.git] / fs / cifs / fscache.c
1 /*
2  *   fs/cifs/fscache.c - CIFS filesystem cache interface
3  *
4  *   Copyright (c) 2010 Novell, Inc.
5  *   Author(s): Suresh Jayaraman <sjayaraman@suse.de>
6  *
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.
11  *
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.
16  *
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
20  */
21 #include "fscache.h"
22 #include "cifsglob.h"
23 #include "cifs_debug.h"
24 #include "cifs_fs_sb.h"
25
26 void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server)
27 {
28         server->fscache =
29                 fscache_acquire_cookie(cifs_fscache_netfs.primary_index,
30                                 &cifs_fscache_server_index_def, server);
31         cFYI(1, "%s: (0x%p/0x%p)", __func__, server,
32                         server->fscache);
33 }
34
35 void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server)
36 {
37         cFYI(1, "%s: (0x%p/0x%p)", __func__, server,
38                         server->fscache);
39         fscache_relinquish_cookie(server->fscache, 0);
40         server->fscache = NULL;
41 }
42
43 void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon)
44 {
45         struct TCP_Server_Info *server = tcon->ses->server;
46
47         tcon->fscache =
48                 fscache_acquire_cookie(server->fscache,
49                                 &cifs_fscache_super_index_def, tcon);
50         cFYI(1, "%s: (0x%p/0x%p)", __func__, server->fscache,
51                         tcon->fscache);
52 }
53
54 void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon)
55 {
56         cFYI(1, "%s: (0x%p)", __func__, tcon->fscache);
57         fscache_relinquish_cookie(tcon->fscache, 0);
58         tcon->fscache = NULL;
59 }
60
61 static void cifs_fscache_enable_inode_cookie(struct inode *inode)
62 {
63         struct cifsInodeInfo *cifsi = CIFS_I(inode);
64         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
65         struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
66
67         if (cifsi->fscache)
68                 return;
69
70         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) {
71                 cifsi->fscache = fscache_acquire_cookie(tcon->fscache,
72                                 &cifs_fscache_inode_object_def, cifsi);
73                 cFYI(1, "%s: got FH cookie (0x%p/0x%p)", __func__,
74                                 tcon->fscache, cifsi->fscache);
75         }
76 }
77
78 void cifs_fscache_release_inode_cookie(struct inode *inode)
79 {
80         struct cifsInodeInfo *cifsi = CIFS_I(inode);
81
82         if (cifsi->fscache) {
83                 cFYI(1, "%s: (0x%p)", __func__, cifsi->fscache);
84                 fscache_relinquish_cookie(cifsi->fscache, 0);
85                 cifsi->fscache = NULL;
86         }
87 }
88
89 static void cifs_fscache_disable_inode_cookie(struct inode *inode)
90 {
91         struct cifsInodeInfo *cifsi = CIFS_I(inode);
92
93         if (cifsi->fscache) {
94                 cFYI(1, "%s: (0x%p)", __func__, cifsi->fscache);
95                 fscache_relinquish_cookie(cifsi->fscache, 1);
96                 cifsi->fscache = NULL;
97         }
98 }
99
100 void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
101 {
102         if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
103                 cifs_fscache_disable_inode_cookie(inode);
104         else
105                 cifs_fscache_enable_inode_cookie(inode);
106 }
107
108 void cifs_fscache_reset_inode_cookie(struct inode *inode)
109 {
110         struct cifsInodeInfo *cifsi = CIFS_I(inode);
111         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
112         struct fscache_cookie *old = cifsi->fscache;
113
114         if (cifsi->fscache) {
115                 /* retire the current fscache cache and get a new one */
116                 fscache_relinquish_cookie(cifsi->fscache, 1);
117
118                 cifsi->fscache = fscache_acquire_cookie(
119                                         cifs_sb_master_tcon(cifs_sb)->fscache,
120                                         &cifs_fscache_inode_object_def,
121                                         cifsi);
122                 cFYI(1, "%s: new cookie 0x%p oldcookie 0x%p",
123                                 __func__, cifsi->fscache, old);
124         }
125 }
126
127 int cifs_fscache_release_page(struct page *page, gfp_t gfp)
128 {
129         if (PageFsCache(page)) {
130                 struct inode *inode = page->mapping->host;
131                 struct cifsInodeInfo *cifsi = CIFS_I(inode);
132
133                 cFYI(1, "%s: (0x%p/0x%p)", __func__, page,
134                                 cifsi->fscache);
135                 if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
136                         return 0;
137         }
138
139         return 1;
140 }
141
142 static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
143                                                 int error)
144 {
145         cFYI(1, "%s: (0x%p/%d)", __func__, page, error);
146         if (!error)
147                 SetPageUptodate(page);
148         unlock_page(page);
149 }
150
151 /*
152  * Retrieve a page from FS-Cache
153  */
154 int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
155 {
156         int ret;
157
158         cFYI(1, "%s: (fsc:%p, p:%p, i:0x%p", __func__,
159                         CIFS_I(inode)->fscache, page, inode);
160         ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
161                                          cifs_readpage_from_fscache_complete,
162                                          NULL,
163                                          GFP_KERNEL);
164         switch (ret) {
165
166         case 0: /* page found in fscache, read submitted */
167                 cFYI(1, "%s: submitted", __func__);
168                 return ret;
169         case -ENOBUFS:  /* page won't be cached */
170         case -ENODATA:  /* page not in cache */
171                 cFYI(1, "%s: %d", __func__, ret);
172                 return 1;
173
174         default:
175                 cERROR(1, "unknown error ret = %d", ret);
176         }
177         return ret;
178 }
179
180 /*
181  * Retrieve a set of pages from FS-Cache
182  */
183 int __cifs_readpages_from_fscache(struct inode *inode,
184                                 struct address_space *mapping,
185                                 struct list_head *pages,
186                                 unsigned *nr_pages)
187 {
188         int ret;
189
190         cFYI(1, "%s: (0x%p/%u/0x%p)", __func__,
191                         CIFS_I(inode)->fscache, *nr_pages, inode);
192         ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
193                                           pages, nr_pages,
194                                           cifs_readpage_from_fscache_complete,
195                                           NULL,
196                                           mapping_gfp_mask(mapping));
197         switch (ret) {
198         case 0: /* read submitted to the cache for all pages */
199                 cFYI(1, "%s: submitted", __func__);
200                 return ret;
201
202         case -ENOBUFS:  /* some pages are not cached and can't be */
203         case -ENODATA:  /* some pages are not cached */
204                 cFYI(1, "%s: no page", __func__);
205                 return 1;
206
207         default:
208                 cFYI(1, "unknown error ret = %d", ret);
209         }
210
211         return ret;
212 }
213
214 void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
215 {
216         int ret;
217
218         cFYI(1, "%s: (fsc: %p, p: %p, i: %p)", __func__,
219                         CIFS_I(inode)->fscache, page, inode);
220         ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL);
221         if (ret != 0)
222                 fscache_uncache_page(CIFS_I(inode)->fscache, page);
223 }
224
225 void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
226 {
227         struct cifsInodeInfo *cifsi = CIFS_I(inode);
228         struct fscache_cookie *cookie = cifsi->fscache;
229
230         cFYI(1, "%s: (0x%p/0x%p)", __func__, page, cookie);
231         fscache_wait_on_page_write(cookie, page);
232         fscache_uncache_page(cookie, page);
233 }
234