138c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1 238c8a9a5SSteve French /* 338c8a9a5SSteve French * CIFS filesystem cache interface 438c8a9a5SSteve French * 538c8a9a5SSteve French * Copyright (c) 2010 Novell, Inc. 638c8a9a5SSteve French * Author(s): Suresh Jayaraman <sjayaraman@suse.de> 738c8a9a5SSteve French * 838c8a9a5SSteve French */ 938c8a9a5SSteve French #include "fscache.h" 1038c8a9a5SSteve French #include "cifsglob.h" 1138c8a9a5SSteve French #include "cifs_debug.h" 1238c8a9a5SSteve French #include "cifs_fs_sb.h" 1338c8a9a5SSteve French #include "cifsproto.h" 1438c8a9a5SSteve French 1538c8a9a5SSteve French static void cifs_fscache_fill_volume_coherency( 1638c8a9a5SSteve French struct cifs_tcon *tcon, 1738c8a9a5SSteve French struct cifs_fscache_volume_coherency_data *cd) 1838c8a9a5SSteve French { 1938c8a9a5SSteve French memset(cd, 0, sizeof(*cd)); 2038c8a9a5SSteve French cd->resource_id = cpu_to_le64(tcon->resource_id); 2138c8a9a5SSteve French cd->vol_create_time = tcon->vol_create_time; 2238c8a9a5SSteve French cd->vol_serial_number = cpu_to_le32(tcon->vol_serial_number); 2338c8a9a5SSteve French } 2438c8a9a5SSteve French 2538c8a9a5SSteve French int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) 2638c8a9a5SSteve French { 2738c8a9a5SSteve French struct cifs_fscache_volume_coherency_data cd; 2838c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 2938c8a9a5SSteve French struct fscache_volume *vcookie; 3038c8a9a5SSteve French const struct sockaddr *sa = (struct sockaddr *)&server->dstaddr; 3138c8a9a5SSteve French size_t slen, i; 3238c8a9a5SSteve French char *sharename; 3338c8a9a5SSteve French char *key; 3438c8a9a5SSteve French int ret = -ENOMEM; 3538c8a9a5SSteve French 3638c8a9a5SSteve French tcon->fscache = NULL; 3738c8a9a5SSteve French switch (sa->sa_family) { 3838c8a9a5SSteve French case AF_INET: 3938c8a9a5SSteve French case AF_INET6: 4038c8a9a5SSteve French break; 4138c8a9a5SSteve French default: 4238c8a9a5SSteve French cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family); 4338c8a9a5SSteve French return -EINVAL; 4438c8a9a5SSteve French } 4538c8a9a5SSteve French 4638c8a9a5SSteve French memset(&key, 0, sizeof(key)); 4738c8a9a5SSteve French 4838c8a9a5SSteve French sharename = extract_sharename(tcon->tree_name); 4938c8a9a5SSteve French if (IS_ERR(sharename)) { 5038c8a9a5SSteve French cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__); 51*efc0b0bcSKatya Orlova return PTR_ERR(sharename); 5238c8a9a5SSteve French } 5338c8a9a5SSteve French 5438c8a9a5SSteve French slen = strlen(sharename); 5538c8a9a5SSteve French for (i = 0; i < slen; i++) 5638c8a9a5SSteve French if (sharename[i] == '/') 5738c8a9a5SSteve French sharename[i] = ';'; 5838c8a9a5SSteve French 5938c8a9a5SSteve French key = kasprintf(GFP_KERNEL, "cifs,%pISpc,%s", sa, sharename); 6038c8a9a5SSteve French if (!key) 6138c8a9a5SSteve French goto out; 6238c8a9a5SSteve French 6338c8a9a5SSteve French cifs_fscache_fill_volume_coherency(tcon, &cd); 6438c8a9a5SSteve French vcookie = fscache_acquire_volume(key, 6538c8a9a5SSteve French NULL, /* preferred_cache */ 6638c8a9a5SSteve French &cd, sizeof(cd)); 6738c8a9a5SSteve French cifs_dbg(FYI, "%s: (%s/0x%p)\n", __func__, key, vcookie); 6838c8a9a5SSteve French if (IS_ERR(vcookie)) { 6938c8a9a5SSteve French if (vcookie != ERR_PTR(-EBUSY)) { 7038c8a9a5SSteve French ret = PTR_ERR(vcookie); 7138c8a9a5SSteve French goto out_2; 7238c8a9a5SSteve French } 7338c8a9a5SSteve French pr_err("Cache volume key already in use (%s)\n", key); 7438c8a9a5SSteve French vcookie = NULL; 7538c8a9a5SSteve French } 7638c8a9a5SSteve French 7738c8a9a5SSteve French tcon->fscache = vcookie; 7838c8a9a5SSteve French ret = 0; 7938c8a9a5SSteve French out_2: 8038c8a9a5SSteve French kfree(key); 8138c8a9a5SSteve French out: 8238c8a9a5SSteve French kfree(sharename); 8338c8a9a5SSteve French return ret; 8438c8a9a5SSteve French } 8538c8a9a5SSteve French 8638c8a9a5SSteve French void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) 8738c8a9a5SSteve French { 8838c8a9a5SSteve French struct cifs_fscache_volume_coherency_data cd; 8938c8a9a5SSteve French 9038c8a9a5SSteve French cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache); 9138c8a9a5SSteve French 9238c8a9a5SSteve French cifs_fscache_fill_volume_coherency(tcon, &cd); 9338c8a9a5SSteve French fscache_relinquish_volume(tcon->fscache, &cd, false); 9438c8a9a5SSteve French tcon->fscache = NULL; 9538c8a9a5SSteve French } 9638c8a9a5SSteve French 9738c8a9a5SSteve French void cifs_fscache_get_inode_cookie(struct inode *inode) 9838c8a9a5SSteve French { 9938c8a9a5SSteve French struct cifs_fscache_inode_coherency_data cd; 10038c8a9a5SSteve French struct cifsInodeInfo *cifsi = CIFS_I(inode); 10138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 10238c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 10338c8a9a5SSteve French 10438c8a9a5SSteve French cifs_fscache_fill_coherency(&cifsi->netfs.inode, &cd); 10538c8a9a5SSteve French 10638c8a9a5SSteve French cifsi->netfs.cache = 10738c8a9a5SSteve French fscache_acquire_cookie(tcon->fscache, 0, 10838c8a9a5SSteve French &cifsi->uniqueid, sizeof(cifsi->uniqueid), 10938c8a9a5SSteve French &cd, sizeof(cd), 11038c8a9a5SSteve French i_size_read(&cifsi->netfs.inode)); 111b4fa966fSDavid Howells if (cifsi->netfs.cache) 112b4fa966fSDavid Howells mapping_set_release_always(inode->i_mapping); 11338c8a9a5SSteve French } 11438c8a9a5SSteve French 11538c8a9a5SSteve French void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) 11638c8a9a5SSteve French { 11738c8a9a5SSteve French if (update) { 11838c8a9a5SSteve French struct cifs_fscache_inode_coherency_data cd; 11938c8a9a5SSteve French loff_t i_size = i_size_read(inode); 12038c8a9a5SSteve French 12138c8a9a5SSteve French cifs_fscache_fill_coherency(inode, &cd); 12238c8a9a5SSteve French fscache_unuse_cookie(cifs_inode_cookie(inode), &cd, &i_size); 12338c8a9a5SSteve French } else { 12438c8a9a5SSteve French fscache_unuse_cookie(cifs_inode_cookie(inode), NULL, NULL); 12538c8a9a5SSteve French } 12638c8a9a5SSteve French } 12738c8a9a5SSteve French 12838c8a9a5SSteve French void cifs_fscache_release_inode_cookie(struct inode *inode) 12938c8a9a5SSteve French { 13038c8a9a5SSteve French struct cifsInodeInfo *cifsi = CIFS_I(inode); 13138c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 13238c8a9a5SSteve French 13338c8a9a5SSteve French if (cookie) { 13438c8a9a5SSteve French cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cookie); 13538c8a9a5SSteve French fscache_relinquish_cookie(cookie, false); 13638c8a9a5SSteve French cifsi->netfs.cache = NULL; 13738c8a9a5SSteve French } 13838c8a9a5SSteve French } 13938c8a9a5SSteve French 14038c8a9a5SSteve French /* 14138c8a9a5SSteve French * Fallback page reading interface. 14238c8a9a5SSteve French */ 14338c8a9a5SSteve French static int fscache_fallback_read_page(struct inode *inode, struct page *page) 14438c8a9a5SSteve French { 14538c8a9a5SSteve French struct netfs_cache_resources cres; 14638c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 14738c8a9a5SSteve French struct iov_iter iter; 14838c8a9a5SSteve French struct bio_vec bvec; 14938c8a9a5SSteve French int ret; 15038c8a9a5SSteve French 15138c8a9a5SSteve French memset(&cres, 0, sizeof(cres)); 15238c8a9a5SSteve French bvec_set_page(&bvec, page, PAGE_SIZE, 0); 15338c8a9a5SSteve French iov_iter_bvec(&iter, ITER_DEST, &bvec, 1, PAGE_SIZE); 15438c8a9a5SSteve French 15538c8a9a5SSteve French ret = fscache_begin_read_operation(&cres, cookie); 15638c8a9a5SSteve French if (ret < 0) 15738c8a9a5SSteve French return ret; 15838c8a9a5SSteve French 15938c8a9a5SSteve French ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL, 16038c8a9a5SSteve French NULL, NULL); 16138c8a9a5SSteve French fscache_end_operation(&cres); 16238c8a9a5SSteve French return ret; 16338c8a9a5SSteve French } 16438c8a9a5SSteve French 16538c8a9a5SSteve French /* 16638c8a9a5SSteve French * Fallback page writing interface. 16738c8a9a5SSteve French */ 16838c8a9a5SSteve French static int fscache_fallback_write_pages(struct inode *inode, loff_t start, size_t len, 16938c8a9a5SSteve French bool no_space_allocated_yet) 17038c8a9a5SSteve French { 17138c8a9a5SSteve French struct netfs_cache_resources cres; 17238c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 17338c8a9a5SSteve French struct iov_iter iter; 17438c8a9a5SSteve French int ret; 17538c8a9a5SSteve French 17638c8a9a5SSteve French memset(&cres, 0, sizeof(cres)); 17738c8a9a5SSteve French iov_iter_xarray(&iter, ITER_SOURCE, &inode->i_mapping->i_pages, start, len); 17838c8a9a5SSteve French 17938c8a9a5SSteve French ret = fscache_begin_write_operation(&cres, cookie); 18038c8a9a5SSteve French if (ret < 0) 18138c8a9a5SSteve French return ret; 18238c8a9a5SSteve French 18338c8a9a5SSteve French ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode), 18438c8a9a5SSteve French no_space_allocated_yet); 18538c8a9a5SSteve French if (ret == 0) 18638c8a9a5SSteve French ret = fscache_write(&cres, start, &iter, NULL, NULL); 18738c8a9a5SSteve French fscache_end_operation(&cres); 18838c8a9a5SSteve French return ret; 18938c8a9a5SSteve French } 19038c8a9a5SSteve French 19138c8a9a5SSteve French /* 19238c8a9a5SSteve French * Retrieve a page from FS-Cache 19338c8a9a5SSteve French */ 19438c8a9a5SSteve French int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) 19538c8a9a5SSteve French { 19638c8a9a5SSteve French int ret; 19738c8a9a5SSteve French 19838c8a9a5SSteve French cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n", 19938c8a9a5SSteve French __func__, cifs_inode_cookie(inode), page, inode); 20038c8a9a5SSteve French 20138c8a9a5SSteve French ret = fscache_fallback_read_page(inode, page); 20238c8a9a5SSteve French if (ret < 0) 20338c8a9a5SSteve French return ret; 20438c8a9a5SSteve French 20538c8a9a5SSteve French /* Read completed synchronously */ 20638c8a9a5SSteve French SetPageUptodate(page); 20738c8a9a5SSteve French return 0; 20838c8a9a5SSteve French } 20938c8a9a5SSteve French 21038c8a9a5SSteve French void __cifs_readahead_to_fscache(struct inode *inode, loff_t pos, size_t len) 21138c8a9a5SSteve French { 21238c8a9a5SSteve French cifs_dbg(FYI, "%s: (fsc: %p, p: %llx, l: %zx, i: %p)\n", 21338c8a9a5SSteve French __func__, cifs_inode_cookie(inode), pos, len, inode); 21438c8a9a5SSteve French 21538c8a9a5SSteve French fscache_fallback_write_pages(inode, pos, len, true); 21638c8a9a5SSteve French } 21738c8a9a5SSteve French 21838c8a9a5SSteve French /* 21938c8a9a5SSteve French * Query the cache occupancy. 22038c8a9a5SSteve French */ 22138c8a9a5SSteve French int __cifs_fscache_query_occupancy(struct inode *inode, 22238c8a9a5SSteve French pgoff_t first, unsigned int nr_pages, 22338c8a9a5SSteve French pgoff_t *_data_first, 22438c8a9a5SSteve French unsigned int *_data_nr_pages) 22538c8a9a5SSteve French { 22638c8a9a5SSteve French struct netfs_cache_resources cres; 22738c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 22838c8a9a5SSteve French loff_t start, data_start; 22938c8a9a5SSteve French size_t len, data_len; 23038c8a9a5SSteve French int ret; 23138c8a9a5SSteve French 23238c8a9a5SSteve French ret = fscache_begin_read_operation(&cres, cookie); 23338c8a9a5SSteve French if (ret < 0) 23438c8a9a5SSteve French return ret; 23538c8a9a5SSteve French 23638c8a9a5SSteve French start = first * PAGE_SIZE; 23738c8a9a5SSteve French len = nr_pages * PAGE_SIZE; 23838c8a9a5SSteve French ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE, 23938c8a9a5SSteve French &data_start, &data_len); 24038c8a9a5SSteve French if (ret == 0) { 24138c8a9a5SSteve French *_data_first = data_start / PAGE_SIZE; 24238c8a9a5SSteve French *_data_nr_pages = len / PAGE_SIZE; 24338c8a9a5SSteve French } 24438c8a9a5SSteve French 24538c8a9a5SSteve French fscache_end_operation(&cres); 24638c8a9a5SSteve French return ret; 24738c8a9a5SSteve French } 248