Back to home page

LXR

 
 

    


0001 /*
0002  * Cleancache frontend
0003  *
0004  * This code provides the generic "frontend" layer to call a matching
0005  * "backend" driver implementation of cleancache.  See
0006  * Documentation/vm/cleancache.txt for more information.
0007  *
0008  * Copyright (C) 2009-2010 Oracle Corp. All rights reserved.
0009  * Author: Dan Magenheimer
0010  *
0011  * This work is licensed under the terms of the GNU GPL, version 2.
0012  */
0013 
0014 #include <linux/module.h>
0015 #include <linux/fs.h>
0016 #include <linux/exportfs.h>
0017 #include <linux/mm.h>
0018 #include <linux/debugfs.h>
0019 #include <linux/cleancache.h>
0020 
0021 /*
0022  * cleancache_ops is set by cleancache_register_ops to contain the pointers
0023  * to the cleancache "backend" implementation functions.
0024  */
0025 static const struct cleancache_ops *cleancache_ops __read_mostly;
0026 
0027 /*
0028  * Counters available via /sys/kernel/debug/cleancache (if debugfs is
0029  * properly configured.  These are for information only so are not protected
0030  * against increment races.
0031  */
0032 static u64 cleancache_succ_gets;
0033 static u64 cleancache_failed_gets;
0034 static u64 cleancache_puts;
0035 static u64 cleancache_invalidates;
0036 
0037 static void cleancache_register_ops_sb(struct super_block *sb, void *unused)
0038 {
0039     switch (sb->cleancache_poolid) {
0040     case CLEANCACHE_NO_BACKEND:
0041         __cleancache_init_fs(sb);
0042         break;
0043     case CLEANCACHE_NO_BACKEND_SHARED:
0044         __cleancache_init_shared_fs(sb);
0045         break;
0046     }
0047 }
0048 
0049 /*
0050  * Register operations for cleancache. Returns 0 on success.
0051  */
0052 int cleancache_register_ops(const struct cleancache_ops *ops)
0053 {
0054     if (cmpxchg(&cleancache_ops, NULL, ops))
0055         return -EBUSY;
0056 
0057     /*
0058      * A cleancache backend can be built as a module and hence loaded after
0059      * a cleancache enabled filesystem has called cleancache_init_fs. To
0060      * handle such a scenario, here we call ->init_fs or ->init_shared_fs
0061      * for each active super block. To differentiate between local and
0062      * shared filesystems, we temporarily initialize sb->cleancache_poolid
0063      * to CLEANCACHE_NO_BACKEND or CLEANCACHE_NO_BACKEND_SHARED
0064      * respectively in case there is no backend registered at the time
0065      * cleancache_init_fs or cleancache_init_shared_fs is called.
0066      *
0067      * Since filesystems can be mounted concurrently with cleancache
0068      * backend registration, we have to be careful to guarantee that all
0069      * cleancache enabled filesystems that has been mounted by the time
0070      * cleancache_register_ops is called has got and all mounted later will
0071      * get cleancache_poolid. This is assured by the following statements
0072      * tied together:
0073      *
0074      * a) iterate_supers skips only those super blocks that has started
0075      *    ->kill_sb
0076      *
0077      * b) if iterate_supers encounters a super block that has not finished
0078      *    ->mount yet, it waits until it is finished
0079      *
0080      * c) cleancache_init_fs is called from ->mount and
0081      *    cleancache_invalidate_fs is called from ->kill_sb
0082      *
0083      * d) we call iterate_supers after cleancache_ops has been set
0084      *
0085      * From a) it follows that if iterate_supers skips a super block, then
0086      * either the super block is already dead, in which case we do not need
0087      * to bother initializing cleancache for it, or it was mounted after we
0088      * initiated iterate_supers. In the latter case, it must have seen
0089      * cleancache_ops set according to d) and initialized cleancache from
0090      * ->mount by itself according to c). This proves that we call
0091      * ->init_fs at least once for each active super block.
0092      *
0093      * From b) and c) it follows that if iterate_supers encounters a super
0094      * block that has already started ->init_fs, it will wait until ->mount
0095      * and hence ->init_fs has finished, then check cleancache_poolid, see
0096      * that it has already been set and therefore do nothing. This proves
0097      * that we call ->init_fs no more than once for each super block.
0098      *
0099      * Combined together, the last two paragraphs prove the function
0100      * correctness.
0101      *
0102      * Note that various cleancache callbacks may proceed before this
0103      * function is called or even concurrently with it, but since
0104      * CLEANCACHE_NO_BACKEND is negative, they will all result in a noop
0105      * until the corresponding ->init_fs has been actually called and
0106      * cleancache_ops has been set.
0107      */
0108     iterate_supers(cleancache_register_ops_sb, NULL);
0109     return 0;
0110 }
0111 EXPORT_SYMBOL(cleancache_register_ops);
0112 
0113 /* Called by a cleancache-enabled filesystem at time of mount */
0114 void __cleancache_init_fs(struct super_block *sb)
0115 {
0116     int pool_id = CLEANCACHE_NO_BACKEND;
0117 
0118     if (cleancache_ops) {
0119         pool_id = cleancache_ops->init_fs(PAGE_SIZE);
0120         if (pool_id < 0)
0121             pool_id = CLEANCACHE_NO_POOL;
0122     }
0123     sb->cleancache_poolid = pool_id;
0124 }
0125 EXPORT_SYMBOL(__cleancache_init_fs);
0126 
0127 /* Called by a cleancache-enabled clustered filesystem at time of mount */
0128 void __cleancache_init_shared_fs(struct super_block *sb)
0129 {
0130     int pool_id = CLEANCACHE_NO_BACKEND_SHARED;
0131 
0132     if (cleancache_ops) {
0133         pool_id = cleancache_ops->init_shared_fs(sb->s_uuid, PAGE_SIZE);
0134         if (pool_id < 0)
0135             pool_id = CLEANCACHE_NO_POOL;
0136     }
0137     sb->cleancache_poolid = pool_id;
0138 }
0139 EXPORT_SYMBOL(__cleancache_init_shared_fs);
0140 
0141 /*
0142  * If the filesystem uses exportable filehandles, use the filehandle as
0143  * the key, else use the inode number.
0144  */
0145 static int cleancache_get_key(struct inode *inode,
0146                   struct cleancache_filekey *key)
0147 {
0148     int (*fhfn)(struct inode *, __u32 *fh, int *, struct inode *);
0149     int len = 0, maxlen = CLEANCACHE_KEY_MAX;
0150     struct super_block *sb = inode->i_sb;
0151 
0152     key->u.ino = inode->i_ino;
0153     if (sb->s_export_op != NULL) {
0154         fhfn = sb->s_export_op->encode_fh;
0155         if  (fhfn) {
0156             len = (*fhfn)(inode, &key->u.fh[0], &maxlen, NULL);
0157             if (len <= FILEID_ROOT || len == FILEID_INVALID)
0158                 return -1;
0159             if (maxlen > CLEANCACHE_KEY_MAX)
0160                 return -1;
0161         }
0162     }
0163     return 0;
0164 }
0165 
0166 /*
0167  * "Get" data from cleancache associated with the poolid/inode/index
0168  * that were specified when the data was put to cleanache and, if
0169  * successful, use it to fill the specified page with data and return 0.
0170  * The pageframe is unchanged and returns -1 if the get fails.
0171  * Page must be locked by caller.
0172  *
0173  * The function has two checks before any action is taken - whether
0174  * a backend is registered and whether the sb->cleancache_poolid
0175  * is correct.
0176  */
0177 int __cleancache_get_page(struct page *page)
0178 {
0179     int ret = -1;
0180     int pool_id;
0181     struct cleancache_filekey key = { .u.key = { 0 } };
0182 
0183     if (!cleancache_ops) {
0184         cleancache_failed_gets++;
0185         goto out;
0186     }
0187 
0188     VM_BUG_ON_PAGE(!PageLocked(page), page);
0189     pool_id = page->mapping->host->i_sb->cleancache_poolid;
0190     if (pool_id < 0)
0191         goto out;
0192 
0193     if (cleancache_get_key(page->mapping->host, &key) < 0)
0194         goto out;
0195 
0196     ret = cleancache_ops->get_page(pool_id, key, page->index, page);
0197     if (ret == 0)
0198         cleancache_succ_gets++;
0199     else
0200         cleancache_failed_gets++;
0201 out:
0202     return ret;
0203 }
0204 EXPORT_SYMBOL(__cleancache_get_page);
0205 
0206 /*
0207  * "Put" data from a page to cleancache and associate it with the
0208  * (previously-obtained per-filesystem) poolid and the page's,
0209  * inode and page index.  Page must be locked.  Note that a put_page
0210  * always "succeeds", though a subsequent get_page may succeed or fail.
0211  *
0212  * The function has two checks before any action is taken - whether
0213  * a backend is registered and whether the sb->cleancache_poolid
0214  * is correct.
0215  */
0216 void __cleancache_put_page(struct page *page)
0217 {
0218     int pool_id;
0219     struct cleancache_filekey key = { .u.key = { 0 } };
0220 
0221     if (!cleancache_ops) {
0222         cleancache_puts++;
0223         return;
0224     }
0225 
0226     VM_BUG_ON_PAGE(!PageLocked(page), page);
0227     pool_id = page->mapping->host->i_sb->cleancache_poolid;
0228     if (pool_id >= 0 &&
0229         cleancache_get_key(page->mapping->host, &key) >= 0) {
0230         cleancache_ops->put_page(pool_id, key, page->index, page);
0231         cleancache_puts++;
0232     }
0233 }
0234 EXPORT_SYMBOL(__cleancache_put_page);
0235 
0236 /*
0237  * Invalidate any data from cleancache associated with the poolid and the
0238  * page's inode and page index so that a subsequent "get" will fail.
0239  *
0240  * The function has two checks before any action is taken - whether
0241  * a backend is registered and whether the sb->cleancache_poolid
0242  * is correct.
0243  */
0244 void __cleancache_invalidate_page(struct address_space *mapping,
0245                     struct page *page)
0246 {
0247     /* careful... page->mapping is NULL sometimes when this is called */
0248     int pool_id = mapping->host->i_sb->cleancache_poolid;
0249     struct cleancache_filekey key = { .u.key = { 0 } };
0250 
0251     if (!cleancache_ops)
0252         return;
0253 
0254     if (pool_id >= 0) {
0255         VM_BUG_ON_PAGE(!PageLocked(page), page);
0256         if (cleancache_get_key(mapping->host, &key) >= 0) {
0257             cleancache_ops->invalidate_page(pool_id,
0258                     key, page->index);
0259             cleancache_invalidates++;
0260         }
0261     }
0262 }
0263 EXPORT_SYMBOL(__cleancache_invalidate_page);
0264 
0265 /*
0266  * Invalidate all data from cleancache associated with the poolid and the
0267  * mappings's inode so that all subsequent gets to this poolid/inode
0268  * will fail.
0269  *
0270  * The function has two checks before any action is taken - whether
0271  * a backend is registered and whether the sb->cleancache_poolid
0272  * is correct.
0273  */
0274 void __cleancache_invalidate_inode(struct address_space *mapping)
0275 {
0276     int pool_id = mapping->host->i_sb->cleancache_poolid;
0277     struct cleancache_filekey key = { .u.key = { 0 } };
0278 
0279     if (!cleancache_ops)
0280         return;
0281 
0282     if (pool_id >= 0 && cleancache_get_key(mapping->host, &key) >= 0)
0283         cleancache_ops->invalidate_inode(pool_id, key);
0284 }
0285 EXPORT_SYMBOL(__cleancache_invalidate_inode);
0286 
0287 /*
0288  * Called by any cleancache-enabled filesystem at time of unmount;
0289  * note that pool_id is surrendered and may be returned by a subsequent
0290  * cleancache_init_fs or cleancache_init_shared_fs.
0291  */
0292 void __cleancache_invalidate_fs(struct super_block *sb)
0293 {
0294     int pool_id;
0295 
0296     pool_id = sb->cleancache_poolid;
0297     sb->cleancache_poolid = CLEANCACHE_NO_POOL;
0298 
0299     if (cleancache_ops && pool_id >= 0)
0300         cleancache_ops->invalidate_fs(pool_id);
0301 }
0302 EXPORT_SYMBOL(__cleancache_invalidate_fs);
0303 
0304 static int __init init_cleancache(void)
0305 {
0306 #ifdef CONFIG_DEBUG_FS
0307     struct dentry *root = debugfs_create_dir("cleancache", NULL);
0308     if (root == NULL)
0309         return -ENXIO;
0310     debugfs_create_u64("succ_gets", S_IRUGO, root, &cleancache_succ_gets);
0311     debugfs_create_u64("failed_gets", S_IRUGO,
0312                 root, &cleancache_failed_gets);
0313     debugfs_create_u64("puts", S_IRUGO, root, &cleancache_puts);
0314     debugfs_create_u64("invalidates", S_IRUGO,
0315                 root, &cleancache_invalidates);
0316 #endif
0317     return 0;
0318 }
0319 module_init(init_cleancache)