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 15614bc8c7SDavid Howells /* 16614bc8c7SDavid Howells * Key for fscache inode. [!] Contents must match comparisons in cifs_find_inode(). 17614bc8c7SDavid Howells */ 18614bc8c7SDavid Howells struct cifs_fscache_inode_key { 19614bc8c7SDavid Howells 20614bc8c7SDavid Howells __le64 uniqueid; /* server inode number */ 21614bc8c7SDavid Howells __le64 createtime; /* creation time on server */ 22614bc8c7SDavid Howells u8 type; /* S_IFMT file type */ 23614bc8c7SDavid Howells } __packed; 24614bc8c7SDavid 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 46*4a5c16d0SDavid Howells if (tcon->fscache_acquired) 47*4a5c16d0SDavid Howells return 0; 48*4a5c16d0SDavid Howells 49*4a5c16d0SDavid Howells mutex_lock(&tcon->fscache_lock); 50*4a5c16d0SDavid Howells if (tcon->fscache_acquired) { 51*4a5c16d0SDavid Howells mutex_unlock(&tcon->fscache_lock); 52*4a5c16d0SDavid Howells return 0; 53*4a5c16d0SDavid Howells } 54*4a5c16d0SDavid Howells tcon->fscache_acquired = true; 55*4a5c16d0SDavid Howells 5638c8a9a5SSteve French tcon->fscache = NULL; 5738c8a9a5SSteve French switch (sa->sa_family) { 5838c8a9a5SSteve French case AF_INET: 5938c8a9a5SSteve French case AF_INET6: 6038c8a9a5SSteve French break; 6138c8a9a5SSteve French default: 62*4a5c16d0SDavid Howells mutex_unlock(&tcon->fscache_lock); 6338c8a9a5SSteve French cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family); 6438c8a9a5SSteve French return -EINVAL; 6538c8a9a5SSteve French } 6638c8a9a5SSteve French 6738c8a9a5SSteve French memset(&key, 0, sizeof(key)); 6838c8a9a5SSteve French 6938c8a9a5SSteve French sharename = extract_sharename(tcon->tree_name); 7038c8a9a5SSteve French if (IS_ERR(sharename)) { 71*4a5c16d0SDavid Howells mutex_unlock(&tcon->fscache_lock); 7238c8a9a5SSteve French cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__); 73efc0b0bcSKatya Orlova return PTR_ERR(sharename); 7438c8a9a5SSteve French } 7538c8a9a5SSteve French 7638c8a9a5SSteve French slen = strlen(sharename); 7738c8a9a5SSteve French for (i = 0; i < slen; i++) 7838c8a9a5SSteve French if (sharename[i] == '/') 7938c8a9a5SSteve French sharename[i] = ';'; 8038c8a9a5SSteve French 8138c8a9a5SSteve French key = kasprintf(GFP_KERNEL, "cifs,%pISpc,%s", sa, sharename); 8238c8a9a5SSteve French if (!key) 8338c8a9a5SSteve French goto out; 8438c8a9a5SSteve French 8538c8a9a5SSteve French cifs_fscache_fill_volume_coherency(tcon, &cd); 8638c8a9a5SSteve French vcookie = fscache_acquire_volume(key, 8738c8a9a5SSteve French NULL, /* preferred_cache */ 8838c8a9a5SSteve French &cd, sizeof(cd)); 8938c8a9a5SSteve French cifs_dbg(FYI, "%s: (%s/0x%p)\n", __func__, key, vcookie); 9038c8a9a5SSteve French if (IS_ERR(vcookie)) { 9138c8a9a5SSteve French if (vcookie != ERR_PTR(-EBUSY)) { 9238c8a9a5SSteve French ret = PTR_ERR(vcookie); 9338c8a9a5SSteve French goto out_2; 9438c8a9a5SSteve French } 9538c8a9a5SSteve French pr_err("Cache volume key already in use (%s)\n", key); 9638c8a9a5SSteve French vcookie = NULL; 9738c8a9a5SSteve French } 9838c8a9a5SSteve French 9938c8a9a5SSteve French tcon->fscache = vcookie; 10038c8a9a5SSteve French ret = 0; 10138c8a9a5SSteve French out_2: 10238c8a9a5SSteve French kfree(key); 10338c8a9a5SSteve French out: 10438c8a9a5SSteve French kfree(sharename); 105*4a5c16d0SDavid Howells mutex_unlock(&tcon->fscache_lock); 10638c8a9a5SSteve French return ret; 10738c8a9a5SSteve French } 10838c8a9a5SSteve French 10938c8a9a5SSteve French void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) 11038c8a9a5SSteve French { 11138c8a9a5SSteve French struct cifs_fscache_volume_coherency_data cd; 11238c8a9a5SSteve French 11338c8a9a5SSteve French cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache); 11438c8a9a5SSteve French 11538c8a9a5SSteve French cifs_fscache_fill_volume_coherency(tcon, &cd); 11638c8a9a5SSteve French fscache_relinquish_volume(tcon->fscache, &cd, false); 11738c8a9a5SSteve French tcon->fscache = NULL; 11838c8a9a5SSteve French } 11938c8a9a5SSteve French 12038c8a9a5SSteve French void cifs_fscache_get_inode_cookie(struct inode *inode) 12138c8a9a5SSteve French { 12238c8a9a5SSteve French struct cifs_fscache_inode_coherency_data cd; 123614bc8c7SDavid Howells struct cifs_fscache_inode_key key; 12438c8a9a5SSteve French struct cifsInodeInfo *cifsi = CIFS_I(inode); 12538c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 12638c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 12738c8a9a5SSteve French 128614bc8c7SDavid Howells key.uniqueid = cpu_to_le64(cifsi->uniqueid); 129614bc8c7SDavid Howells key.createtime = cpu_to_le64(cifsi->createtime); 130614bc8c7SDavid Howells key.type = (inode->i_mode & S_IFMT) >> 12; 13138c8a9a5SSteve French cifs_fscache_fill_coherency(&cifsi->netfs.inode, &cd); 13238c8a9a5SSteve French 13338c8a9a5SSteve French cifsi->netfs.cache = 13438c8a9a5SSteve French fscache_acquire_cookie(tcon->fscache, 0, 135614bc8c7SDavid Howells &key, sizeof(key), 13638c8a9a5SSteve French &cd, sizeof(cd), 13738c8a9a5SSteve French i_size_read(&cifsi->netfs.inode)); 138b4fa966fSDavid Howells if (cifsi->netfs.cache) 139b4fa966fSDavid Howells mapping_set_release_always(inode->i_mapping); 14038c8a9a5SSteve French } 14138c8a9a5SSteve French 14238c8a9a5SSteve French void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) 14338c8a9a5SSteve French { 14438c8a9a5SSteve French if (update) { 14538c8a9a5SSteve French struct cifs_fscache_inode_coherency_data cd; 14638c8a9a5SSteve French loff_t i_size = i_size_read(inode); 14738c8a9a5SSteve French 14838c8a9a5SSteve French cifs_fscache_fill_coherency(inode, &cd); 14938c8a9a5SSteve French fscache_unuse_cookie(cifs_inode_cookie(inode), &cd, &i_size); 15038c8a9a5SSteve French } else { 15138c8a9a5SSteve French fscache_unuse_cookie(cifs_inode_cookie(inode), NULL, NULL); 15238c8a9a5SSteve French } 15338c8a9a5SSteve French } 15438c8a9a5SSteve French 15538c8a9a5SSteve French void cifs_fscache_release_inode_cookie(struct inode *inode) 15638c8a9a5SSteve French { 15738c8a9a5SSteve French struct cifsInodeInfo *cifsi = CIFS_I(inode); 15838c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 15938c8a9a5SSteve French 16038c8a9a5SSteve French if (cookie) { 16138c8a9a5SSteve French cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cookie); 16238c8a9a5SSteve French fscache_relinquish_cookie(cookie, false); 16338c8a9a5SSteve French cifsi->netfs.cache = NULL; 16438c8a9a5SSteve French } 16538c8a9a5SSteve French } 16638c8a9a5SSteve French 16738c8a9a5SSteve French /* 16838c8a9a5SSteve French * Fallback page reading interface. 16938c8a9a5SSteve French */ 17038c8a9a5SSteve French static int fscache_fallback_read_page(struct inode *inode, struct page *page) 17138c8a9a5SSteve French { 17238c8a9a5SSteve French struct netfs_cache_resources cres; 17338c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 17438c8a9a5SSteve French struct iov_iter iter; 17538c8a9a5SSteve French struct bio_vec bvec; 17638c8a9a5SSteve French int ret; 17738c8a9a5SSteve French 17838c8a9a5SSteve French memset(&cres, 0, sizeof(cres)); 17938c8a9a5SSteve French bvec_set_page(&bvec, page, PAGE_SIZE, 0); 18038c8a9a5SSteve French iov_iter_bvec(&iter, ITER_DEST, &bvec, 1, PAGE_SIZE); 18138c8a9a5SSteve French 18238c8a9a5SSteve French ret = fscache_begin_read_operation(&cres, cookie); 18338c8a9a5SSteve French if (ret < 0) 18438c8a9a5SSteve French return ret; 18538c8a9a5SSteve French 18638c8a9a5SSteve French ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL, 18738c8a9a5SSteve French NULL, NULL); 18838c8a9a5SSteve French fscache_end_operation(&cres); 18938c8a9a5SSteve French return ret; 19038c8a9a5SSteve French } 19138c8a9a5SSteve French 19238c8a9a5SSteve French /* 19338c8a9a5SSteve French * Fallback page writing interface. 19438c8a9a5SSteve French */ 19538c8a9a5SSteve French static int fscache_fallback_write_pages(struct inode *inode, loff_t start, size_t len, 19638c8a9a5SSteve French bool no_space_allocated_yet) 19738c8a9a5SSteve French { 19838c8a9a5SSteve French struct netfs_cache_resources cres; 19938c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 20038c8a9a5SSteve French struct iov_iter iter; 20138c8a9a5SSteve French int ret; 20238c8a9a5SSteve French 20338c8a9a5SSteve French memset(&cres, 0, sizeof(cres)); 20438c8a9a5SSteve French iov_iter_xarray(&iter, ITER_SOURCE, &inode->i_mapping->i_pages, start, len); 20538c8a9a5SSteve French 20638c8a9a5SSteve French ret = fscache_begin_write_operation(&cres, cookie); 20738c8a9a5SSteve French if (ret < 0) 20838c8a9a5SSteve French return ret; 20938c8a9a5SSteve French 21038c8a9a5SSteve French ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode), 21138c8a9a5SSteve French no_space_allocated_yet); 21238c8a9a5SSteve French if (ret == 0) 21338c8a9a5SSteve French ret = fscache_write(&cres, start, &iter, NULL, NULL); 21438c8a9a5SSteve French fscache_end_operation(&cres); 21538c8a9a5SSteve French return ret; 21638c8a9a5SSteve French } 21738c8a9a5SSteve French 21838c8a9a5SSteve French /* 21938c8a9a5SSteve French * Retrieve a page from FS-Cache 22038c8a9a5SSteve French */ 22138c8a9a5SSteve French int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) 22238c8a9a5SSteve French { 22338c8a9a5SSteve French int ret; 22438c8a9a5SSteve French 22538c8a9a5SSteve French cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n", 22638c8a9a5SSteve French __func__, cifs_inode_cookie(inode), page, inode); 22738c8a9a5SSteve French 22838c8a9a5SSteve French ret = fscache_fallback_read_page(inode, page); 22938c8a9a5SSteve French if (ret < 0) 23038c8a9a5SSteve French return ret; 23138c8a9a5SSteve French 23238c8a9a5SSteve French /* Read completed synchronously */ 23338c8a9a5SSteve French SetPageUptodate(page); 23438c8a9a5SSteve French return 0; 23538c8a9a5SSteve French } 23638c8a9a5SSteve French 23738c8a9a5SSteve French void __cifs_readahead_to_fscache(struct inode *inode, loff_t pos, size_t len) 23838c8a9a5SSteve French { 23938c8a9a5SSteve French cifs_dbg(FYI, "%s: (fsc: %p, p: %llx, l: %zx, i: %p)\n", 24038c8a9a5SSteve French __func__, cifs_inode_cookie(inode), pos, len, inode); 24138c8a9a5SSteve French 24238c8a9a5SSteve French fscache_fallback_write_pages(inode, pos, len, true); 24338c8a9a5SSteve French } 24438c8a9a5SSteve French 24538c8a9a5SSteve French /* 24638c8a9a5SSteve French * Query the cache occupancy. 24738c8a9a5SSteve French */ 24838c8a9a5SSteve French int __cifs_fscache_query_occupancy(struct inode *inode, 24938c8a9a5SSteve French pgoff_t first, unsigned int nr_pages, 25038c8a9a5SSteve French pgoff_t *_data_first, 25138c8a9a5SSteve French unsigned int *_data_nr_pages) 25238c8a9a5SSteve French { 25338c8a9a5SSteve French struct netfs_cache_resources cres; 25438c8a9a5SSteve French struct fscache_cookie *cookie = cifs_inode_cookie(inode); 25538c8a9a5SSteve French loff_t start, data_start; 25638c8a9a5SSteve French size_t len, data_len; 25738c8a9a5SSteve French int ret; 25838c8a9a5SSteve French 25938c8a9a5SSteve French ret = fscache_begin_read_operation(&cres, cookie); 26038c8a9a5SSteve French if (ret < 0) 26138c8a9a5SSteve French return ret; 26238c8a9a5SSteve French 26338c8a9a5SSteve French start = first * PAGE_SIZE; 26438c8a9a5SSteve French len = nr_pages * PAGE_SIZE; 26538c8a9a5SSteve French ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE, 26638c8a9a5SSteve French &data_start, &data_len); 26738c8a9a5SSteve French if (ret == 0) { 26838c8a9a5SSteve French *_data_first = data_start / PAGE_SIZE; 26938c8a9a5SSteve French *_data_nr_pages = len / PAGE_SIZE; 27038c8a9a5SSteve French } 27138c8a9a5SSteve French 27238c8a9a5SSteve French fscache_end_operation(&cres); 27338c8a9a5SSteve French return ret; 27438c8a9a5SSteve French } 275