Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: LGPL-2.1
0002 /*
0003  *   CIFS filesystem cache interface
0004  *
0005  *   Copyright (c) 2010 Novell, Inc.
0006  *   Author(s): Suresh Jayaraman <sjayaraman@suse.de>
0007  *
0008  */
0009 #include "fscache.h"
0010 #include "cifsglob.h"
0011 #include "cifs_debug.h"
0012 #include "cifs_fs_sb.h"
0013 #include "cifsproto.h"
0014 
0015 static void cifs_fscache_fill_volume_coherency(
0016     struct cifs_tcon *tcon,
0017     struct cifs_fscache_volume_coherency_data *cd)
0018 {
0019     memset(cd, 0, sizeof(*cd));
0020     cd->resource_id     = cpu_to_le64(tcon->resource_id);
0021     cd->vol_create_time = tcon->vol_create_time;
0022     cd->vol_serial_number   = cpu_to_le32(tcon->vol_serial_number);
0023 }
0024 
0025 int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon)
0026 {
0027     struct cifs_fscache_volume_coherency_data cd;
0028     struct TCP_Server_Info *server = tcon->ses->server;
0029     struct fscache_volume *vcookie;
0030     const struct sockaddr *sa = (struct sockaddr *)&server->dstaddr;
0031     size_t slen, i;
0032     char *sharename;
0033     char *key;
0034     int ret = -ENOMEM;
0035 
0036     tcon->fscache = NULL;
0037     switch (sa->sa_family) {
0038     case AF_INET:
0039     case AF_INET6:
0040         break;
0041     default:
0042         cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family);
0043         return -EINVAL;
0044     }
0045 
0046     memset(&key, 0, sizeof(key));
0047 
0048     sharename = extract_sharename(tcon->treeName);
0049     if (IS_ERR(sharename)) {
0050         cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__);
0051         return -EINVAL;
0052     }
0053 
0054     slen = strlen(sharename);
0055     for (i = 0; i < slen; i++)
0056         if (sharename[i] == '/')
0057             sharename[i] = ';';
0058 
0059     key = kasprintf(GFP_KERNEL, "cifs,%pISpc,%s", sa, sharename);
0060     if (!key)
0061         goto out;
0062 
0063     cifs_fscache_fill_volume_coherency(tcon, &cd);
0064     vcookie = fscache_acquire_volume(key,
0065                      NULL, /* preferred_cache */
0066                      &cd, sizeof(cd));
0067     cifs_dbg(FYI, "%s: (%s/0x%p)\n", __func__, key, vcookie);
0068     if (IS_ERR(vcookie)) {
0069         if (vcookie != ERR_PTR(-EBUSY)) {
0070             ret = PTR_ERR(vcookie);
0071             goto out_2;
0072         }
0073         pr_err("Cache volume key already in use (%s)\n", key);
0074         vcookie = NULL;
0075     }
0076 
0077     tcon->fscache = vcookie;
0078     ret = 0;
0079 out_2:
0080     kfree(key);
0081 out:
0082     kfree(sharename);
0083     return ret;
0084 }
0085 
0086 void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon)
0087 {
0088     struct cifs_fscache_volume_coherency_data cd;
0089 
0090     cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache);
0091 
0092     cifs_fscache_fill_volume_coherency(tcon, &cd);
0093     fscache_relinquish_volume(tcon->fscache, &cd, false);
0094     tcon->fscache = NULL;
0095 }
0096 
0097 void cifs_fscache_get_inode_cookie(struct inode *inode)
0098 {
0099     struct cifs_fscache_inode_coherency_data cd;
0100     struct cifsInodeInfo *cifsi = CIFS_I(inode);
0101     struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
0102     struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
0103 
0104     cifs_fscache_fill_coherency(&cifsi->netfs.inode, &cd);
0105 
0106     cifsi->netfs.cache =
0107         fscache_acquire_cookie(tcon->fscache, 0,
0108                        &cifsi->uniqueid, sizeof(cifsi->uniqueid),
0109                        &cd, sizeof(cd),
0110                        i_size_read(&cifsi->netfs.inode));
0111 }
0112 
0113 void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update)
0114 {
0115     if (update) {
0116         struct cifs_fscache_inode_coherency_data cd;
0117         loff_t i_size = i_size_read(inode);
0118 
0119         cifs_fscache_fill_coherency(inode, &cd);
0120         fscache_unuse_cookie(cifs_inode_cookie(inode), &cd, &i_size);
0121     } else {
0122         fscache_unuse_cookie(cifs_inode_cookie(inode), NULL, NULL);
0123     }
0124 }
0125 
0126 void cifs_fscache_release_inode_cookie(struct inode *inode)
0127 {
0128     struct cifsInodeInfo *cifsi = CIFS_I(inode);
0129     struct fscache_cookie *cookie = cifs_inode_cookie(inode);
0130 
0131     if (cookie) {
0132         cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cookie);
0133         fscache_relinquish_cookie(cookie, false);
0134         cifsi->netfs.cache = NULL;
0135     }
0136 }
0137 
0138 /*
0139  * Fallback page reading interface.
0140  */
0141 static int fscache_fallback_read_page(struct inode *inode, struct page *page)
0142 {
0143     struct netfs_cache_resources cres;
0144     struct fscache_cookie *cookie = cifs_inode_cookie(inode);
0145     struct iov_iter iter;
0146     struct bio_vec bvec[1];
0147     int ret;
0148 
0149     memset(&cres, 0, sizeof(cres));
0150     bvec[0].bv_page     = page;
0151     bvec[0].bv_offset   = 0;
0152     bvec[0].bv_len      = PAGE_SIZE;
0153     iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
0154 
0155     ret = fscache_begin_read_operation(&cres, cookie);
0156     if (ret < 0)
0157         return ret;
0158 
0159     ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL,
0160                NULL, NULL);
0161     fscache_end_operation(&cres);
0162     return ret;
0163 }
0164 
0165 /*
0166  * Fallback page writing interface.
0167  */
0168 static int fscache_fallback_write_page(struct inode *inode, struct page *page,
0169                        bool no_space_allocated_yet)
0170 {
0171     struct netfs_cache_resources cres;
0172     struct fscache_cookie *cookie = cifs_inode_cookie(inode);
0173     struct iov_iter iter;
0174     struct bio_vec bvec[1];
0175     loff_t start = page_offset(page);
0176     size_t len = PAGE_SIZE;
0177     int ret;
0178 
0179     memset(&cres, 0, sizeof(cres));
0180     bvec[0].bv_page     = page;
0181     bvec[0].bv_offset   = 0;
0182     bvec[0].bv_len      = PAGE_SIZE;
0183     iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
0184 
0185     ret = fscache_begin_write_operation(&cres, cookie);
0186     if (ret < 0)
0187         return ret;
0188 
0189     ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode),
0190                       no_space_allocated_yet);
0191     if (ret == 0)
0192         ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL);
0193     fscache_end_operation(&cres);
0194     return ret;
0195 }
0196 
0197 /*
0198  * Retrieve a page from FS-Cache
0199  */
0200 int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
0201 {
0202     int ret;
0203 
0204     cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
0205          __func__, cifs_inode_cookie(inode), page, inode);
0206 
0207     ret = fscache_fallback_read_page(inode, page);
0208     if (ret < 0)
0209         return ret;
0210 
0211     /* Read completed synchronously */
0212     SetPageUptodate(page);
0213     return 0;
0214 }
0215 
0216 void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
0217 {
0218     cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n",
0219          __func__, cifs_inode_cookie(inode), page, inode);
0220 
0221     fscache_fallback_write_page(inode, page, true);
0222 }
0223 
0224 /*
0225  * Query the cache occupancy.
0226  */
0227 int __cifs_fscache_query_occupancy(struct inode *inode,
0228                    pgoff_t first, unsigned int nr_pages,
0229                    pgoff_t *_data_first,
0230                    unsigned int *_data_nr_pages)
0231 {
0232     struct netfs_cache_resources cres;
0233     struct fscache_cookie *cookie = cifs_inode_cookie(inode);
0234     loff_t start, data_start;
0235     size_t len, data_len;
0236     int ret;
0237 
0238     ret = fscache_begin_read_operation(&cres, cookie);
0239     if (ret < 0)
0240         return ret;
0241 
0242     start = first * PAGE_SIZE;
0243     len = nr_pages * PAGE_SIZE;
0244     ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE,
0245                     &data_start, &data_len);
0246     if (ret == 0) {
0247         *_data_first = data_start / PAGE_SIZE;
0248         *_data_nr_pages = len / PAGE_SIZE;
0249     }
0250 
0251     fscache_end_operation(&cres);
0252     return ret;
0253 }