Steve French | 929be90 | 2021-06-18 00:31:49 -0500 | [diff] [blame] | 1 | // SPDX-License-Identifier: LGPL-2.1 |
Suresh Jayaraman | 488f1d2d | 2010-07-05 18:12:15 +0530 | [diff] [blame] | 2 | /* |
Steve French | 099dd78 | 2021-09-13 14:51:10 -0500 | [diff] [blame] | 3 | * CIFS filesystem cache interface |
Suresh Jayaraman | 488f1d2d | 2010-07-05 18:12:15 +0530 | [diff] [blame] | 4 | * |
| 5 | * Copyright (c) 2010 Novell, Inc. |
Suresh Jayaraman | b81209d | 2010-11-24 17:49:06 +0530 | [diff] [blame] | 6 | * Author(s): Suresh Jayaraman <sjayaraman@suse.de> |
Suresh Jayaraman | 488f1d2d | 2010-07-05 18:12:15 +0530 | [diff] [blame] | 7 | * |
Suresh Jayaraman | 488f1d2d | 2010-07-05 18:12:15 +0530 | [diff] [blame] | 8 | */ |
| 9 | #include "fscache.h" |
| 10 | #include "cifsglob.h" |
| 11 | #include "cifs_debug.h" |
Suresh Jayaraman | 9451a9a | 2010-07-05 18:12:45 +0530 | [diff] [blame] | 12 | #include "cifs_fs_sb.h" |
Samuel Cabrero | e73a42e | 2020-11-30 19:02:48 +0100 | [diff] [blame] | 13 | #include "cifsproto.h" |
Suresh Jayaraman | 488f1d2d | 2010-07-05 18:12:15 +0530 | [diff] [blame] | 14 | |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 15 | static void cifs_fscache_fill_volume_coherency( |
| 16 | struct cifs_tcon *tcon, |
| 17 | struct cifs_fscache_volume_coherency_data *cd) |
Suresh Jayaraman | 488f1d2d | 2010-07-05 18:12:15 +0530 | [diff] [blame] | 18 | { |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 19 | memset(cd, 0, sizeof(*cd)); |
| 20 | cd->resource_id = cpu_to_le64(tcon->resource_id); |
| 21 | cd->vol_create_time = tcon->vol_create_time; |
| 22 | cd->vol_serial_number = cpu_to_le32(tcon->vol_serial_number); |
| 23 | } |
David Howells | 402cb8d | 2018-04-04 13:41:28 +0100 | [diff] [blame] | 24 | |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 25 | int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) |
| 26 | { |
| 27 | struct cifs_fscache_volume_coherency_data cd; |
| 28 | struct TCP_Server_Info *server = tcon->ses->server; |
| 29 | struct fscache_volume *vcookie; |
| 30 | const struct sockaddr *sa = (struct sockaddr *)&server->dstaddr; |
| 31 | size_t slen, i; |
| 32 | char *sharename; |
| 33 | char *key; |
| 34 | int ret = -ENOMEM; |
| 35 | |
| 36 | tcon->fscache = NULL; |
| 37 | switch (sa->sa_family) { |
| 38 | case AF_INET: |
| 39 | case AF_INET6: |
| 40 | break; |
| 41 | default: |
| 42 | cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family); |
| 43 | return -EINVAL; |
| 44 | } |
Shyam Prasad N | 2adc820 | 2021-12-02 07:30:00 +0000 | [diff] [blame] | 45 | |
David Howells | 402cb8d | 2018-04-04 13:41:28 +0100 | [diff] [blame] | 46 | memset(&key, 0, sizeof(key)); |
Steve French | 0210274 | 2021-11-10 03:15:29 -0600 | [diff] [blame] | 47 | |
David Howells | 402cb8d | 2018-04-04 13:41:28 +0100 | [diff] [blame] | 48 | sharename = extract_sharename(tcon->treeName); |
| 49 | if (IS_ERR(sharename)) { |
| 50 | cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__); |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 51 | return -EINVAL; |
David Howells | 402cb8d | 2018-04-04 13:41:28 +0100 | [diff] [blame] | 52 | } |
Suresh Jayaraman | d03382c | 2010-07-05 18:12:27 +0530 | [diff] [blame] | 53 | |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 54 | slen = strlen(sharename); |
| 55 | for (i = 0; i < slen; i++) |
| 56 | if (sharename[i] == '/') |
| 57 | sharename[i] = ';'; |
Steve French | 5865985 | 2020-06-05 17:19:46 -0500 | [diff] [blame] | 58 | |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 59 | key = kasprintf(GFP_KERNEL, "cifs,%pISpc,%s", sa, sharename); |
| 60 | if (!key) |
| 61 | goto out; |
| 62 | |
| 63 | cifs_fscache_fill_volume_coherency(tcon, &cd); |
| 64 | vcookie = fscache_acquire_volume(key, |
| 65 | NULL, /* preferred_cache */ |
| 66 | &cd, sizeof(cd)); |
| 67 | cifs_dbg(FYI, "%s: (%s/0x%p)\n", __func__, key, vcookie); |
| 68 | if (IS_ERR(vcookie)) { |
| 69 | if (vcookie != ERR_PTR(-EBUSY)) { |
| 70 | ret = PTR_ERR(vcookie); |
| 71 | goto out_2; |
| 72 | } |
| 73 | pr_err("Cache volume key already in use (%s)\n", key); |
| 74 | vcookie = NULL; |
| 75 | } |
| 76 | |
| 77 | tcon->fscache = vcookie; |
| 78 | ret = 0; |
| 79 | out_2: |
| 80 | kfree(key); |
| 81 | out: |
David Howells | 402cb8d | 2018-04-04 13:41:28 +0100 | [diff] [blame] | 82 | kfree(sharename); |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 83 | return ret; |
Suresh Jayaraman | d03382c | 2010-07-05 18:12:27 +0530 | [diff] [blame] | 84 | } |
| 85 | |
Steve French | 96daf2b | 2011-05-27 04:34:02 +0000 | [diff] [blame] | 86 | void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) |
Suresh Jayaraman | d03382c | 2010-07-05 18:12:27 +0530 | [diff] [blame] | 87 | { |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 88 | struct cifs_fscache_volume_coherency_data cd; |
Steve French | 5865985 | 2020-06-05 17:19:46 -0500 | [diff] [blame] | 89 | |
Joe Perches | f96637b | 2013-05-04 22:12:25 -0500 | [diff] [blame] | 90 | cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache); |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 91 | |
| 92 | cifs_fscache_fill_volume_coherency(tcon, &cd); |
| 93 | fscache_relinquish_volume(tcon->fscache, &cd, false); |
Suresh Jayaraman | d03382c | 2010-07-05 18:12:27 +0530 | [diff] [blame] | 94 | tcon->fscache = NULL; |
| 95 | } |
Suresh Jayaraman | 9451a9a | 2010-07-05 18:12:45 +0530 | [diff] [blame] | 96 | |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 97 | void cifs_fscache_get_inode_cookie(struct inode *inode) |
David Howells | 402cb8d | 2018-04-04 13:41:28 +0100 | [diff] [blame] | 98 | { |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 99 | struct cifs_fscache_inode_coherency_data cd; |
Suresh Jayaraman | 9451a9a | 2010-07-05 18:12:45 +0530 | [diff] [blame] | 100 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
| 101 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
Steve French | 96daf2b | 2011-05-27 04:34:02 +0000 | [diff] [blame] | 102 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
Suresh Jayaraman | 9451a9a | 2010-07-05 18:12:45 +0530 | [diff] [blame] | 103 | |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 104 | cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd); |
Suresh Jayaraman | 9451a9a | 2010-07-05 18:12:45 +0530 | [diff] [blame] | 105 | |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 106 | cifsi->fscache = |
| 107 | fscache_acquire_cookie(tcon->fscache, 0, |
| 108 | &cifsi->uniqueid, sizeof(cifsi->uniqueid), |
| 109 | &cd, sizeof(cd), |
| 110 | i_size_read(&cifsi->vfs_inode)); |
| 111 | } |
David Howells | 402cb8d | 2018-04-04 13:41:28 +0100 | [diff] [blame] | 112 | |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 113 | void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) |
| 114 | { |
| 115 | if (update) { |
| 116 | struct cifs_fscache_inode_coherency_data cd; |
| 117 | loff_t i_size = i_size_read(inode); |
David Howells | 402cb8d | 2018-04-04 13:41:28 +0100 | [diff] [blame] | 118 | |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 119 | cifs_fscache_fill_coherency(inode, &cd); |
| 120 | fscache_unuse_cookie(cifs_inode_cookie(inode), &cd, &i_size); |
| 121 | } else { |
| 122 | fscache_unuse_cookie(cifs_inode_cookie(inode), NULL, NULL); |
| 123 | } |
Suresh Jayaraman | 9451a9a | 2010-07-05 18:12:45 +0530 | [diff] [blame] | 124 | } |
| 125 | |
| 126 | void cifs_fscache_release_inode_cookie(struct inode *inode) |
| 127 | { |
| 128 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
| 129 | |
| 130 | if (cifsi->fscache) { |
Joe Perches | f96637b | 2013-05-04 22:12:25 -0500 | [diff] [blame] | 131 | cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache); |
David Howells | 70431bf | 2020-11-17 15:56:59 +0000 | [diff] [blame] | 132 | fscache_relinquish_cookie(cifsi->fscache, false); |
Suresh Jayaraman | 9451a9a | 2010-07-05 18:12:45 +0530 | [diff] [blame] | 133 | cifsi->fscache = NULL; |
| 134 | } |
| 135 | } |
| 136 | |
David Howells | 0174ee9 | 2022-01-27 16:02:58 +0000 | [diff] [blame] | 137 | static inline void fscache_end_operation(struct netfs_cache_resources *cres) |
| 138 | { |
| 139 | const struct netfs_cache_ops *ops = fscache_operation_valid(cres); |
| 140 | |
| 141 | if (ops) |
| 142 | ops->end_operation(cres); |
| 143 | } |
| 144 | |
| 145 | /* |
| 146 | * Fallback page reading interface. |
| 147 | */ |
| 148 | static int fscache_fallback_read_page(struct inode *inode, struct page *page) |
| 149 | { |
| 150 | struct netfs_cache_resources cres; |
| 151 | struct fscache_cookie *cookie = cifs_inode_cookie(inode); |
| 152 | struct iov_iter iter; |
| 153 | struct bio_vec bvec[1]; |
| 154 | int ret; |
| 155 | |
| 156 | memset(&cres, 0, sizeof(cres)); |
| 157 | bvec[0].bv_page = page; |
| 158 | bvec[0].bv_offset = 0; |
| 159 | bvec[0].bv_len = PAGE_SIZE; |
| 160 | iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE); |
| 161 | |
| 162 | ret = fscache_begin_read_operation(&cres, cookie); |
| 163 | if (ret < 0) |
| 164 | return ret; |
| 165 | |
| 166 | ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL, |
| 167 | NULL, NULL); |
| 168 | fscache_end_operation(&cres); |
| 169 | return ret; |
| 170 | } |
| 171 | |
| 172 | /* |
| 173 | * Fallback page writing interface. |
| 174 | */ |
| 175 | static int fscache_fallback_write_page(struct inode *inode, struct page *page, |
| 176 | bool no_space_allocated_yet) |
| 177 | { |
| 178 | struct netfs_cache_resources cres; |
| 179 | struct fscache_cookie *cookie = cifs_inode_cookie(inode); |
| 180 | struct iov_iter iter; |
| 181 | struct bio_vec bvec[1]; |
| 182 | loff_t start = page_offset(page); |
| 183 | size_t len = PAGE_SIZE; |
| 184 | int ret; |
| 185 | |
| 186 | memset(&cres, 0, sizeof(cres)); |
| 187 | bvec[0].bv_page = page; |
| 188 | bvec[0].bv_offset = 0; |
| 189 | bvec[0].bv_len = PAGE_SIZE; |
| 190 | iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE); |
| 191 | |
| 192 | ret = fscache_begin_write_operation(&cres, cookie); |
| 193 | if (ret < 0) |
| 194 | return ret; |
| 195 | |
| 196 | ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode), |
| 197 | no_space_allocated_yet); |
| 198 | if (ret == 0) |
| 199 | ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL); |
| 200 | fscache_end_operation(&cres); |
| 201 | return ret; |
| 202 | } |
| 203 | |
Suresh Jayaraman | 56698236 | 2010-07-05 18:13:25 +0530 | [diff] [blame] | 204 | /* |
| 205 | * Retrieve a page from FS-Cache |
| 206 | */ |
| 207 | int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) |
| 208 | { |
David Howells | 0174ee9 | 2022-01-27 16:02:58 +0000 | [diff] [blame] | 209 | int ret; |
Suresh Jayaraman | 56698236 | 2010-07-05 18:13:25 +0530 | [diff] [blame] | 210 | |
David Howells | 0174ee9 | 2022-01-27 16:02:58 +0000 | [diff] [blame] | 211 | cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n", |
| 212 | __func__, cifs_inode_cookie(inode), page, inode); |
| 213 | |
| 214 | ret = fscache_fallback_read_page(inode, page); |
| 215 | if (ret < 0) |
| 216 | return ret; |
| 217 | |
| 218 | /* Read completed synchronously */ |
| 219 | SetPageUptodate(page); |
| 220 | return 0; |
Suresh Jayaraman | 56698236 | 2010-07-05 18:13:25 +0530 | [diff] [blame] | 221 | } |
| 222 | |
Suresh Jayaraman | 9dc0655 | 2010-07-05 18:13:11 +0530 | [diff] [blame] | 223 | void __cifs_readpage_to_fscache(struct inode *inode, struct page *page) |
| 224 | { |
Joe Perches | f96637b | 2013-05-04 22:12:25 -0500 | [diff] [blame] | 225 | cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n", |
David Howells | 0174ee9 | 2022-01-27 16:02:58 +0000 | [diff] [blame] | 226 | __func__, cifs_inode_cookie(inode), page, inode); |
Suresh Jayaraman | 9dc0655 | 2010-07-05 18:13:11 +0530 | [diff] [blame] | 227 | |
David Howells | 0174ee9 | 2022-01-27 16:02:58 +0000 | [diff] [blame] | 228 | fscache_fallback_write_page(inode, page, true); |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 | * Query the cache occupancy. |
| 233 | */ |
| 234 | int __cifs_fscache_query_occupancy(struct inode *inode, |
| 235 | pgoff_t first, unsigned int nr_pages, |
| 236 | pgoff_t *_data_first, |
| 237 | unsigned int *_data_nr_pages) |
| 238 | { |
| 239 | struct netfs_cache_resources cres; |
| 240 | struct fscache_cookie *cookie = cifs_inode_cookie(inode); |
| 241 | loff_t start, data_start; |
| 242 | size_t len, data_len; |
| 243 | int ret; |
| 244 | |
| 245 | ret = fscache_begin_read_operation(&cres, cookie); |
| 246 | if (ret < 0) |
| 247 | return ret; |
| 248 | |
| 249 | start = first * PAGE_SIZE; |
| 250 | len = nr_pages * PAGE_SIZE; |
| 251 | ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE, |
| 252 | &data_start, &data_len); |
| 253 | if (ret == 0) { |
| 254 | *_data_first = data_start / PAGE_SIZE; |
| 255 | *_data_nr_pages = len / PAGE_SIZE; |
| 256 | } |
| 257 | |
| 258 | fscache_end_operation(&cres); |
| 259 | return ret; |
Shyam Prasad N | 18d0406 | 2021-08-10 10:22:28 +0000 | [diff] [blame] | 260 | } |