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 15*614bc8c7SDavid Howells /* 16*614bc8c7SDavid Howells * Key for fscache inode. [!] Contents must match comparisons in cifs_find_inode(). 17*614bc8c7SDavid Howells */ 18*614bc8c7SDavid Howells struct cifs_fscache_inode_key { 19*614bc8c7SDavid Howells 20*614bc8c7SDavid Howells __le64 uniqueid; /* server inode number */ 21*614bc8c7SDavid Howells __le64 createtime; /* creation time on server */ 22*614bc8c7SDavid Howells u8 type; /* S_IFMT file type */ 23*614bc8c7SDavid Howells } __packed; 24*614bc8c7SDavid Howells 2538c8a9a5SSteve French static void cifs_fscache_fill_volume_coherency( 2638c8a9a5SSteve French struct cifs_tcon *tcon, 2738c8a9a5SSteve French struct cifs_fscache_volume_coherency_data *cd) 2838c8a9a5SSteve French { 2938c8a9a5SSteve French memset(cd, 0, sizeof(*cd)); 3038c8a9a5SSteve French cd->resource_id = cpu_to_le64(tcon->resource_id); 3138c8a9a5SSteve French cd->vol_create_time = tcon->vol_create_time; 3238c8a9a5SSteve French cd->vol_serial_number = cpu_to_le32(tcon->vol_serial_number); 3338c8a9a5SSteve French } 3438c8a9a5SSteve French 3538c8a9a5SSteve French int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) 3638c8a9a5SSteve French { 3738c8a9a5SSteve French struct cifs_fscache_volume_coherency_data cd; 3838c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 3938c8a9a5SSteve French struct fscache_volume *vcookie; 4038c8a9a5SSteve French const struct sockaddr *sa = (struct sockaddr *)&server->dstaddr; 4138c8a9a5SSteve French size_t slen, i; 4238c8a9a5SSteve French char *sharename; 4338c8a9a5SSteve French char *key; 4438c8a9a5SSteve French int ret = -ENOMEM; 4538c8a9a5SSteve French 4638c8a9a5SSteve French tcon->fscache = NULL; 4738c8a9a5SSteve French switch (sa->sa_family) { 4838c8a9a5SSteve French case AF_INET: 4938c8a9a5SSteve French case AF_INET6: 5038c8a9a5SSteve French break; 5138c8a9a5SSteve French default: 5238c8a9a5SSteve French cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family); 5338c8a9a5SSteve French return -EINVAL; 5438c8a9a5SSteve French } 5538c8a9a5SSteve French 5638c8a9a5SSteve French memset(&key, 0, sizeof(key)); 5738c8a9a5SSteve French 5838c8a9a5SSteve French sharename = extract_sharename(tcon->tree_name); 5938c8a9a5SSteve French if (IS_ERR(sharename)) { 6038c8a9a5SSteve French cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__); 61efc0b0bcSKatya Orlova return PTR_ERR(sharename); 6238c8a9a5SSteve French } 6338c8a9a5SSteve French 6438c8a9a5SSteve French slen = strlen(sharename); 6538c8a9a5SSteve French for (i = 0; i < slen; i++) 6638c8a9a5SSteve French if (sharename[i] == '/') 6738c8a9a5SSteve French sharename[i] = ';'; 6838c8a9a5SSteve French 6938c8a9a5SSteve French key = kasprintf(GFP_KERNEL, "cifs,%pISpc,%s", sa, sharename); 7038c8a9a5SSteve French if (!key) 7138c8a9a5SSteve French goto out; 7238c8a9a5SSteve French 7338c8a9a5SSteve French cifs_fscache_fill_volume_coherency(tcon, &cd); 7438c8a9a5SSteve French vcookie = fscache_acquire_volume(key, 7538c8a9a5SSteve French NULL, /* preferred_cache */ 7638c8a9a5SSteve French &cd, sizeof(cd)); 7738c8a9a5SSteve French cifs_dbg(FYI, "%s: (%s/0x%p)\n", __func__, key, vcookie); 7838c8a9a5SSteve French if (IS_ERR(vcookie)) { 7938c8a9a5SSteve French if (vcookie != ERR_PTR(-EBUSY)) { 8038c8a9a5SSteve French ret = PTR_ERR(vcookie); 8138c8a9a5SSteve French goto out_2; 8238c8a9a5SSteve French } 8338c8a9a5SSteve French pr_err("Cache volume key already in use (%s)\n", key); 8438c8a9a5SSteve French vcookie = NULL; 8538c8a9a5SSteve French } 8638c8a9a5SSteve French 8738c8a9a5SSteve French tcon->fscache = vcookie; 8838c8a9a5SSteve French ret = 0; 8938c8a9a5SSteve French out_2: 9038c8a9a5SSteve French kfree(key); 9138c8a9a5SSteve French out: 9238c8a9a5SSteve French kfree(sharename); 9338c8a9a5SSteve French return ret; 9438c8a9a5SSteve French } 9538c8a9a5SSteve French 9638c8a9a5SSteve French void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) 9738c8a9a5SSteve French { 9838c8a9a5SSteve French struct cifs_fscache_volume_coherency_data cd; 9938c8a9a5SSteve French 10038c8a9a5SSteve French cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache); 10138c8a9a5SSteve French 10238c8a9a5SSteve French cifs_fscache_fill_volume_coherency(tcon, &cd); 10338c8a9a5SSteve French fscache_relinquish_volume(tcon->fscache, &cd, false); 10438c8a9a5SSteve French tcon->fscache = NULL; 10538c8a9a5SSteve French } 10638c8a9a5SSteve French 10738c8a9a5SSteve French void cifs_fscache_get_inode_cookie(struct inode *inode) 10838c8a9a5SSteve French { 10938c8a9a5SSteve French struct cifs_fscache_inode_coherency_data cd; 110*614bc8c7SDavid Howells struct cifs_fscache_inode_key key; 11138c8a9a5SSteve French struct cifsInodeInfo *cifsi = CIFS_I(inode); 11238c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 11338c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 11438c8a9a5SSteve French 115*614bc8c7SDavid Howells key.uniqueid = cpu_to_le64(cifsi->uniqueid); 116*614bc8c7SDavid Howells key.createtime = cpu_to_le64(cifsi->createtime); 117*614bc8c7SDavid Howells key.type = (inode->i_mode & S_IFMT) >> 12; 11838c8a9a5SSteve French cifs_fscache_fill_coherency(&cifsi->netfs.inode, &cd); 11938c8a9a5SSteve French 12038c8a9a5SSteve French cifsi->netfs.cache = 12138c8a9a5SSteve French fscache_acquire_cookie(tcon->fscache, 0, 122*614bc8c7SDavid Howells &key, sizeof(key), 12338c8a9a5SSteve French &cd, sizeof(cd), 12438c8a9a5SSteve French i_size_read(&cifsi->netfs.inode)); 125b4fa966fSDavid Howells if (cifsi->netfs.cache) 126b4fa966fSDavid Howells mapping_set_release_always(inode->i_mapping); 12738c8a9a5SSteve French } 12838c8a9a5SSteve French 12938c8a9a5SSteve French void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) 13038c8a9a5SSteve French { 13138c8a9a5SSteve French if (update) { 13238c8a9a5SSteve French struct cifs_fscache_inode_coherency_data cd; 13338c8a9a5SSteve French loff_t i_size = i_size_read(inode); 13438c8a9a5SSteve French 13538c8a9a5SSteve French cifs_fscache_fill_coherency(inode, &cd); 13638c8a9a5SSteve French fscache_unuse_cookie(cifs_inode_cookie(inode), &cd, &i_size); 13738c8a9a5SSteve French } else { 13838c8a9a5SSteve French fscache_unuse_cookie(cifs_inode_cookie(inode), NULL, NULL); 13938c8a9a5SSteve French } 14038c8a9a5SSteve French } 14138c8a9a5SSteve French 14238c8a9a5SSteve French void cifs_fscache_release_inode_cookie(struct inode *inode) 14338c8a9a5SSteve French { 14438c8a9a5SSteve French struct cifsInodeInfo *cifsi = CIFS_I(inode); 14538c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 14638c8a9a5SSteve French 14738c8a9a5SSteve French if (cookie) { 14838c8a9a5SSteve French cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cookie); 14938c8a9a5SSteve French fscache_relinquish_cookie(cookie, false); 15038c8a9a5SSteve French cifsi->netfs.cache = NULL; 15138c8a9a5SSteve French } 15238c8a9a5SSteve French } 15338c8a9a5SSteve French 15438c8a9a5SSteve French /* 15538c8a9a5SSteve French * Fallback page reading interface. 15638c8a9a5SSteve French */ 15738c8a9a5SSteve French static int fscache_fallback_read_page(struct inode *inode, struct page *page) 15838c8a9a5SSteve French { 15938c8a9a5SSteve French struct netfs_cache_resources cres; 16038c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 16138c8a9a5SSteve French struct iov_iter iter; 16238c8a9a5SSteve French struct bio_vec bvec; 16338c8a9a5SSteve French int ret; 16438c8a9a5SSteve French 16538c8a9a5SSteve French memset(&cres, 0, sizeof(cres)); 16638c8a9a5SSteve French bvec_set_page(&bvec, page, PAGE_SIZE, 0); 16738c8a9a5SSteve French iov_iter_bvec(&iter, ITER_DEST, &bvec, 1, PAGE_SIZE); 16838c8a9a5SSteve French 16938c8a9a5SSteve French ret = fscache_begin_read_operation(&cres, cookie); 17038c8a9a5SSteve French if (ret < 0) 17138c8a9a5SSteve French return ret; 17238c8a9a5SSteve French 17338c8a9a5SSteve French ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL, 17438c8a9a5SSteve French NULL, NULL); 17538c8a9a5SSteve French fscache_end_operation(&cres); 17638c8a9a5SSteve French return ret; 17738c8a9a5SSteve French } 17838c8a9a5SSteve French 17938c8a9a5SSteve French /* 18038c8a9a5SSteve French * Fallback page writing interface. 18138c8a9a5SSteve French */ 18238c8a9a5SSteve French static int fscache_fallback_write_pages(struct inode *inode, loff_t start, size_t len, 18338c8a9a5SSteve French bool no_space_allocated_yet) 18438c8a9a5SSteve French { 18538c8a9a5SSteve French struct netfs_cache_resources cres; 18638c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 18738c8a9a5SSteve French struct iov_iter iter; 18838c8a9a5SSteve French int ret; 18938c8a9a5SSteve French 19038c8a9a5SSteve French memset(&cres, 0, sizeof(cres)); 19138c8a9a5SSteve French iov_iter_xarray(&iter, ITER_SOURCE, &inode->i_mapping->i_pages, start, len); 19238c8a9a5SSteve French 19338c8a9a5SSteve French ret = fscache_begin_write_operation(&cres, cookie); 19438c8a9a5SSteve French if (ret < 0) 19538c8a9a5SSteve French return ret; 19638c8a9a5SSteve French 19738c8a9a5SSteve French ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode), 19838c8a9a5SSteve French no_space_allocated_yet); 19938c8a9a5SSteve French if (ret == 0) 20038c8a9a5SSteve French ret = fscache_write(&cres, start, &iter, NULL, NULL); 20138c8a9a5SSteve French fscache_end_operation(&cres); 20238c8a9a5SSteve French return ret; 20338c8a9a5SSteve French } 20438c8a9a5SSteve French 20538c8a9a5SSteve French /* 20638c8a9a5SSteve French * Retrieve a page from FS-Cache 20738c8a9a5SSteve French */ 20838c8a9a5SSteve French int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) 20938c8a9a5SSteve French { 21038c8a9a5SSteve French int ret; 21138c8a9a5SSteve French 21238c8a9a5SSteve French cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n", 21338c8a9a5SSteve French __func__, cifs_inode_cookie(inode), page, inode); 21438c8a9a5SSteve French 21538c8a9a5SSteve French ret = fscache_fallback_read_page(inode, page); 21638c8a9a5SSteve French if (ret < 0) 21738c8a9a5SSteve French return ret; 21838c8a9a5SSteve French 21938c8a9a5SSteve French /* Read completed synchronously */ 22038c8a9a5SSteve French SetPageUptodate(page); 22138c8a9a5SSteve French return 0; 22238c8a9a5SSteve French } 22338c8a9a5SSteve French 22438c8a9a5SSteve French void __cifs_readahead_to_fscache(struct inode *inode, loff_t pos, size_t len) 22538c8a9a5SSteve French { 22638c8a9a5SSteve French cifs_dbg(FYI, "%s: (fsc: %p, p: %llx, l: %zx, i: %p)\n", 22738c8a9a5SSteve French __func__, cifs_inode_cookie(inode), pos, len, inode); 22838c8a9a5SSteve French 22938c8a9a5SSteve French fscache_fallback_write_pages(inode, pos, len, true); 23038c8a9a5SSteve French } 23138c8a9a5SSteve French 23238c8a9a5SSteve French /* 23338c8a9a5SSteve French * Query the cache occupancy. 23438c8a9a5SSteve French */ 23538c8a9a5SSteve French int __cifs_fscache_query_occupancy(struct inode *inode, 23638c8a9a5SSteve French pgoff_t first, unsigned int nr_pages, 23738c8a9a5SSteve French pgoff_t *_data_first, 23838c8a9a5SSteve French unsigned int *_data_nr_pages) 23938c8a9a5SSteve French { 24038c8a9a5SSteve French struct netfs_cache_resources cres; 24138c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 24238c8a9a5SSteve French loff_t start, data_start; 24338c8a9a5SSteve French size_t len, data_len; 24438c8a9a5SSteve French int ret; 24538c8a9a5SSteve French 24638c8a9a5SSteve French ret = fscache_begin_read_operation(&cres, cookie); 24738c8a9a5SSteve French if (ret < 0) 24838c8a9a5SSteve French return ret; 24938c8a9a5SSteve French 25038c8a9a5SSteve French start = first * PAGE_SIZE; 25138c8a9a5SSteve French len = nr_pages * PAGE_SIZE; 25238c8a9a5SSteve French ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE, 25338c8a9a5SSteve French &data_start, &data_len); 25438c8a9a5SSteve French if (ret == 0) { 25538c8a9a5SSteve French *_data_first = data_start / PAGE_SIZE; 25638c8a9a5SSteve French *_data_nr_pages = len / PAGE_SIZE; 25738c8a9a5SSteve French } 25838c8a9a5SSteve French 25938c8a9a5SSteve French fscache_end_operation(&cres); 26038c8a9a5SSteve French return ret; 26138c8a9a5SSteve French } 262