root/fs/cachefiles/daemon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cachefiles_daemon_open
  2. cachefiles_daemon_release
  3. cachefiles_daemon_read
  4. cachefiles_daemon_write
  5. cachefiles_daemon_poll
  6. cachefiles_daemon_range_error
  7. cachefiles_daemon_frun
  8. cachefiles_daemon_fcull
  9. cachefiles_daemon_fstop
  10. cachefiles_daemon_brun
  11. cachefiles_daemon_bcull
  12. cachefiles_daemon_bstop
  13. cachefiles_daemon_dir
  14. cachefiles_daemon_secctx
  15. cachefiles_daemon_tag
  16. cachefiles_daemon_cull
  17. cachefiles_daemon_debug
  18. cachefiles_daemon_inuse
  19. cachefiles_has_space

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* Daemon interface
   3  *
   4  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   5  * Written by David Howells (dhowells@redhat.com)
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/init.h>
  10 #include <linux/sched.h>
  11 #include <linux/completion.h>
  12 #include <linux/slab.h>
  13 #include <linux/fs.h>
  14 #include <linux/file.h>
  15 #include <linux/namei.h>
  16 #include <linux/poll.h>
  17 #include <linux/mount.h>
  18 #include <linux/statfs.h>
  19 #include <linux/ctype.h>
  20 #include <linux/string.h>
  21 #include <linux/fs_struct.h>
  22 #include "internal.h"
  23 
  24 static int cachefiles_daemon_open(struct inode *, struct file *);
  25 static int cachefiles_daemon_release(struct inode *, struct file *);
  26 static ssize_t cachefiles_daemon_read(struct file *, char __user *, size_t,
  27                                       loff_t *);
  28 static ssize_t cachefiles_daemon_write(struct file *, const char __user *,
  29                                        size_t, loff_t *);
  30 static __poll_t cachefiles_daemon_poll(struct file *,
  31                                            struct poll_table_struct *);
  32 static int cachefiles_daemon_frun(struct cachefiles_cache *, char *);
  33 static int cachefiles_daemon_fcull(struct cachefiles_cache *, char *);
  34 static int cachefiles_daemon_fstop(struct cachefiles_cache *, char *);
  35 static int cachefiles_daemon_brun(struct cachefiles_cache *, char *);
  36 static int cachefiles_daemon_bcull(struct cachefiles_cache *, char *);
  37 static int cachefiles_daemon_bstop(struct cachefiles_cache *, char *);
  38 static int cachefiles_daemon_cull(struct cachefiles_cache *, char *);
  39 static int cachefiles_daemon_debug(struct cachefiles_cache *, char *);
  40 static int cachefiles_daemon_dir(struct cachefiles_cache *, char *);
  41 static int cachefiles_daemon_inuse(struct cachefiles_cache *, char *);
  42 static int cachefiles_daemon_secctx(struct cachefiles_cache *, char *);
  43 static int cachefiles_daemon_tag(struct cachefiles_cache *, char *);
  44 
  45 static unsigned long cachefiles_open;
  46 
  47 const struct file_operations cachefiles_daemon_fops = {
  48         .owner          = THIS_MODULE,
  49         .open           = cachefiles_daemon_open,
  50         .release        = cachefiles_daemon_release,
  51         .read           = cachefiles_daemon_read,
  52         .write          = cachefiles_daemon_write,
  53         .poll           = cachefiles_daemon_poll,
  54         .llseek         = noop_llseek,
  55 };
  56 
  57 struct cachefiles_daemon_cmd {
  58         char name[8];
  59         int (*handler)(struct cachefiles_cache *cache, char *args);
  60 };
  61 
  62 static const struct cachefiles_daemon_cmd cachefiles_daemon_cmds[] = {
  63         { "bind",       cachefiles_daemon_bind          },
  64         { "brun",       cachefiles_daemon_brun          },
  65         { "bcull",      cachefiles_daemon_bcull         },
  66         { "bstop",      cachefiles_daemon_bstop         },
  67         { "cull",       cachefiles_daemon_cull          },
  68         { "debug",      cachefiles_daemon_debug         },
  69         { "dir",        cachefiles_daemon_dir           },
  70         { "frun",       cachefiles_daemon_frun          },
  71         { "fcull",      cachefiles_daemon_fcull         },
  72         { "fstop",      cachefiles_daemon_fstop         },
  73         { "inuse",      cachefiles_daemon_inuse         },
  74         { "secctx",     cachefiles_daemon_secctx        },
  75         { "tag",        cachefiles_daemon_tag           },
  76         { "",           NULL                            }
  77 };
  78 
  79 
  80 /*
  81  * do various checks
  82  */
  83 static int cachefiles_daemon_open(struct inode *inode, struct file *file)
  84 {
  85         struct cachefiles_cache *cache;
  86 
  87         _enter("");
  88 
  89         /* only the superuser may do this */
  90         if (!capable(CAP_SYS_ADMIN))
  91                 return -EPERM;
  92 
  93         /* the cachefiles device may only be open once at a time */
  94         if (xchg(&cachefiles_open, 1) == 1)
  95                 return -EBUSY;
  96 
  97         /* allocate a cache record */
  98         cache = kzalloc(sizeof(struct cachefiles_cache), GFP_KERNEL);
  99         if (!cache) {
 100                 cachefiles_open = 0;
 101                 return -ENOMEM;
 102         }
 103 
 104         mutex_init(&cache->daemon_mutex);
 105         cache->active_nodes = RB_ROOT;
 106         rwlock_init(&cache->active_lock);
 107         init_waitqueue_head(&cache->daemon_pollwq);
 108 
 109         /* set default caching limits
 110          * - limit at 1% free space and/or free files
 111          * - cull below 5% free space and/or free files
 112          * - cease culling above 7% free space and/or free files
 113          */
 114         cache->frun_percent = 7;
 115         cache->fcull_percent = 5;
 116         cache->fstop_percent = 1;
 117         cache->brun_percent = 7;
 118         cache->bcull_percent = 5;
 119         cache->bstop_percent = 1;
 120 
 121         file->private_data = cache;
 122         cache->cachefilesd = file;
 123         return 0;
 124 }
 125 
 126 /*
 127  * release a cache
 128  */
 129 static int cachefiles_daemon_release(struct inode *inode, struct file *file)
 130 {
 131         struct cachefiles_cache *cache = file->private_data;
 132 
 133         _enter("");
 134 
 135         ASSERT(cache);
 136 
 137         set_bit(CACHEFILES_DEAD, &cache->flags);
 138 
 139         cachefiles_daemon_unbind(cache);
 140 
 141         ASSERT(!cache->active_nodes.rb_node);
 142 
 143         /* clean up the control file interface */
 144         cache->cachefilesd = NULL;
 145         file->private_data = NULL;
 146         cachefiles_open = 0;
 147 
 148         kfree(cache);
 149 
 150         _leave("");
 151         return 0;
 152 }
 153 
 154 /*
 155  * read the cache state
 156  */
 157 static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer,
 158                                       size_t buflen, loff_t *pos)
 159 {
 160         struct cachefiles_cache *cache = file->private_data;
 161         unsigned long long b_released;
 162         unsigned f_released;
 163         char buffer[256];
 164         int n;
 165 
 166         //_enter(",,%zu,", buflen);
 167 
 168         if (!test_bit(CACHEFILES_READY, &cache->flags))
 169                 return 0;
 170 
 171         /* check how much space the cache has */
 172         cachefiles_has_space(cache, 0, 0);
 173 
 174         /* summarise */
 175         f_released = atomic_xchg(&cache->f_released, 0);
 176         b_released = atomic_long_xchg(&cache->b_released, 0);
 177         clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags);
 178 
 179         n = snprintf(buffer, sizeof(buffer),
 180                      "cull=%c"
 181                      " frun=%llx"
 182                      " fcull=%llx"
 183                      " fstop=%llx"
 184                      " brun=%llx"
 185                      " bcull=%llx"
 186                      " bstop=%llx"
 187                      " freleased=%x"
 188                      " breleased=%llx",
 189                      test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0',
 190                      (unsigned long long) cache->frun,
 191                      (unsigned long long) cache->fcull,
 192                      (unsigned long long) cache->fstop,
 193                      (unsigned long long) cache->brun,
 194                      (unsigned long long) cache->bcull,
 195                      (unsigned long long) cache->bstop,
 196                      f_released,
 197                      b_released);
 198 
 199         if (n > buflen)
 200                 return -EMSGSIZE;
 201 
 202         if (copy_to_user(_buffer, buffer, n) != 0)
 203                 return -EFAULT;
 204 
 205         return n;
 206 }
 207 
 208 /*
 209  * command the cache
 210  */
 211 static ssize_t cachefiles_daemon_write(struct file *file,
 212                                        const char __user *_data,
 213                                        size_t datalen,
 214                                        loff_t *pos)
 215 {
 216         const struct cachefiles_daemon_cmd *cmd;
 217         struct cachefiles_cache *cache = file->private_data;
 218         ssize_t ret;
 219         char *data, *args, *cp;
 220 
 221         //_enter(",,%zu,", datalen);
 222 
 223         ASSERT(cache);
 224 
 225         if (test_bit(CACHEFILES_DEAD, &cache->flags))
 226                 return -EIO;
 227 
 228         if (datalen < 0 || datalen > PAGE_SIZE - 1)
 229                 return -EOPNOTSUPP;
 230 
 231         /* drag the command string into the kernel so we can parse it */
 232         data = memdup_user_nul(_data, datalen);
 233         if (IS_ERR(data))
 234                 return PTR_ERR(data);
 235 
 236         ret = -EINVAL;
 237         if (memchr(data, '\0', datalen))
 238                 goto error;
 239 
 240         /* strip any newline */
 241         cp = memchr(data, '\n', datalen);
 242         if (cp) {
 243                 if (cp == data)
 244                         goto error;
 245 
 246                 *cp = '\0';
 247         }
 248 
 249         /* parse the command */
 250         ret = -EOPNOTSUPP;
 251 
 252         for (args = data; *args; args++)
 253                 if (isspace(*args))
 254                         break;
 255         if (*args) {
 256                 if (args == data)
 257                         goto error;
 258                 *args = '\0';
 259                 args = skip_spaces(++args);
 260         }
 261 
 262         /* run the appropriate command handler */
 263         for (cmd = cachefiles_daemon_cmds; cmd->name[0]; cmd++)
 264                 if (strcmp(cmd->name, data) == 0)
 265                         goto found_command;
 266 
 267 error:
 268         kfree(data);
 269         //_leave(" = %zd", ret);
 270         return ret;
 271 
 272 found_command:
 273         mutex_lock(&cache->daemon_mutex);
 274 
 275         ret = -EIO;
 276         if (!test_bit(CACHEFILES_DEAD, &cache->flags))
 277                 ret = cmd->handler(cache, args);
 278 
 279         mutex_unlock(&cache->daemon_mutex);
 280 
 281         if (ret == 0)
 282                 ret = datalen;
 283         goto error;
 284 }
 285 
 286 /*
 287  * poll for culling state
 288  * - use EPOLLOUT to indicate culling state
 289  */
 290 static __poll_t cachefiles_daemon_poll(struct file *file,
 291                                            struct poll_table_struct *poll)
 292 {
 293         struct cachefiles_cache *cache = file->private_data;
 294         __poll_t mask;
 295 
 296         poll_wait(file, &cache->daemon_pollwq, poll);
 297         mask = 0;
 298 
 299         if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags))
 300                 mask |= EPOLLIN;
 301 
 302         if (test_bit(CACHEFILES_CULLING, &cache->flags))
 303                 mask |= EPOLLOUT;
 304 
 305         return mask;
 306 }
 307 
 308 /*
 309  * give a range error for cache space constraints
 310  * - can be tail-called
 311  */
 312 static int cachefiles_daemon_range_error(struct cachefiles_cache *cache,
 313                                          char *args)
 314 {
 315         pr_err("Free space limits must be in range 0%%<=stop<cull<run<100%%\n");
 316 
 317         return -EINVAL;
 318 }
 319 
 320 /*
 321  * set the percentage of files at which to stop culling
 322  * - command: "frun <N>%"
 323  */
 324 static int cachefiles_daemon_frun(struct cachefiles_cache *cache, char *args)
 325 {
 326         unsigned long frun;
 327 
 328         _enter(",%s", args);
 329 
 330         if (!*args)
 331                 return -EINVAL;
 332 
 333         frun = simple_strtoul(args, &args, 10);
 334         if (args[0] != '%' || args[1] != '\0')
 335                 return -EINVAL;
 336 
 337         if (frun <= cache->fcull_percent || frun >= 100)
 338                 return cachefiles_daemon_range_error(cache, args);
 339 
 340         cache->frun_percent = frun;
 341         return 0;
 342 }
 343 
 344 /*
 345  * set the percentage of files at which to start culling
 346  * - command: "fcull <N>%"
 347  */
 348 static int cachefiles_daemon_fcull(struct cachefiles_cache *cache, char *args)
 349 {
 350         unsigned long fcull;
 351 
 352         _enter(",%s", args);
 353 
 354         if (!*args)
 355                 return -EINVAL;
 356 
 357         fcull = simple_strtoul(args, &args, 10);
 358         if (args[0] != '%' || args[1] != '\0')
 359                 return -EINVAL;
 360 
 361         if (fcull <= cache->fstop_percent || fcull >= cache->frun_percent)
 362                 return cachefiles_daemon_range_error(cache, args);
 363 
 364         cache->fcull_percent = fcull;
 365         return 0;
 366 }
 367 
 368 /*
 369  * set the percentage of files at which to stop allocating
 370  * - command: "fstop <N>%"
 371  */
 372 static int cachefiles_daemon_fstop(struct cachefiles_cache *cache, char *args)
 373 {
 374         unsigned long fstop;
 375 
 376         _enter(",%s", args);
 377 
 378         if (!*args)
 379                 return -EINVAL;
 380 
 381         fstop = simple_strtoul(args, &args, 10);
 382         if (args[0] != '%' || args[1] != '\0')
 383                 return -EINVAL;
 384 
 385         if (fstop < 0 || fstop >= cache->fcull_percent)
 386                 return cachefiles_daemon_range_error(cache, args);
 387 
 388         cache->fstop_percent = fstop;
 389         return 0;
 390 }
 391 
 392 /*
 393  * set the percentage of blocks at which to stop culling
 394  * - command: "brun <N>%"
 395  */
 396 static int cachefiles_daemon_brun(struct cachefiles_cache *cache, char *args)
 397 {
 398         unsigned long brun;
 399 
 400         _enter(",%s", args);
 401 
 402         if (!*args)
 403                 return -EINVAL;
 404 
 405         brun = simple_strtoul(args, &args, 10);
 406         if (args[0] != '%' || args[1] != '\0')
 407                 return -EINVAL;
 408 
 409         if (brun <= cache->bcull_percent || brun >= 100)
 410                 return cachefiles_daemon_range_error(cache, args);
 411 
 412         cache->brun_percent = brun;
 413         return 0;
 414 }
 415 
 416 /*
 417  * set the percentage of blocks at which to start culling
 418  * - command: "bcull <N>%"
 419  */
 420 static int cachefiles_daemon_bcull(struct cachefiles_cache *cache, char *args)
 421 {
 422         unsigned long bcull;
 423 
 424         _enter(",%s", args);
 425 
 426         if (!*args)
 427                 return -EINVAL;
 428 
 429         bcull = simple_strtoul(args, &args, 10);
 430         if (args[0] != '%' || args[1] != '\0')
 431                 return -EINVAL;
 432 
 433         if (bcull <= cache->bstop_percent || bcull >= cache->brun_percent)
 434                 return cachefiles_daemon_range_error(cache, args);
 435 
 436         cache->bcull_percent = bcull;
 437         return 0;
 438 }
 439 
 440 /*
 441  * set the percentage of blocks at which to stop allocating
 442  * - command: "bstop <N>%"
 443  */
 444 static int cachefiles_daemon_bstop(struct cachefiles_cache *cache, char *args)
 445 {
 446         unsigned long bstop;
 447 
 448         _enter(",%s", args);
 449 
 450         if (!*args)
 451                 return -EINVAL;
 452 
 453         bstop = simple_strtoul(args, &args, 10);
 454         if (args[0] != '%' || args[1] != '\0')
 455                 return -EINVAL;
 456 
 457         if (bstop < 0 || bstop >= cache->bcull_percent)
 458                 return cachefiles_daemon_range_error(cache, args);
 459 
 460         cache->bstop_percent = bstop;
 461         return 0;
 462 }
 463 
 464 /*
 465  * set the cache directory
 466  * - command: "dir <name>"
 467  */
 468 static int cachefiles_daemon_dir(struct cachefiles_cache *cache, char *args)
 469 {
 470         char *dir;
 471 
 472         _enter(",%s", args);
 473 
 474         if (!*args) {
 475                 pr_err("Empty directory specified\n");
 476                 return -EINVAL;
 477         }
 478 
 479         if (cache->rootdirname) {
 480                 pr_err("Second cache directory specified\n");
 481                 return -EEXIST;
 482         }
 483 
 484         dir = kstrdup(args, GFP_KERNEL);
 485         if (!dir)
 486                 return -ENOMEM;
 487 
 488         cache->rootdirname = dir;
 489         return 0;
 490 }
 491 
 492 /*
 493  * set the cache security context
 494  * - command: "secctx <ctx>"
 495  */
 496 static int cachefiles_daemon_secctx(struct cachefiles_cache *cache, char *args)
 497 {
 498         char *secctx;
 499 
 500         _enter(",%s", args);
 501 
 502         if (!*args) {
 503                 pr_err("Empty security context specified\n");
 504                 return -EINVAL;
 505         }
 506 
 507         if (cache->secctx) {
 508                 pr_err("Second security context specified\n");
 509                 return -EINVAL;
 510         }
 511 
 512         secctx = kstrdup(args, GFP_KERNEL);
 513         if (!secctx)
 514                 return -ENOMEM;
 515 
 516         cache->secctx = secctx;
 517         return 0;
 518 }
 519 
 520 /*
 521  * set the cache tag
 522  * - command: "tag <name>"
 523  */
 524 static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args)
 525 {
 526         char *tag;
 527 
 528         _enter(",%s", args);
 529 
 530         if (!*args) {
 531                 pr_err("Empty tag specified\n");
 532                 return -EINVAL;
 533         }
 534 
 535         if (cache->tag)
 536                 return -EEXIST;
 537 
 538         tag = kstrdup(args, GFP_KERNEL);
 539         if (!tag)
 540                 return -ENOMEM;
 541 
 542         cache->tag = tag;
 543         return 0;
 544 }
 545 
 546 /*
 547  * request a node in the cache be culled from the current working directory
 548  * - command: "cull <name>"
 549  */
 550 static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args)
 551 {
 552         struct path path;
 553         const struct cred *saved_cred;
 554         int ret;
 555 
 556         _enter(",%s", args);
 557 
 558         if (strchr(args, '/'))
 559                 goto inval;
 560 
 561         if (!test_bit(CACHEFILES_READY, &cache->flags)) {
 562                 pr_err("cull applied to unready cache\n");
 563                 return -EIO;
 564         }
 565 
 566         if (test_bit(CACHEFILES_DEAD, &cache->flags)) {
 567                 pr_err("cull applied to dead cache\n");
 568                 return -EIO;
 569         }
 570 
 571         /* extract the directory dentry from the cwd */
 572         get_fs_pwd(current->fs, &path);
 573 
 574         if (!d_can_lookup(path.dentry))
 575                 goto notdir;
 576 
 577         cachefiles_begin_secure(cache, &saved_cred);
 578         ret = cachefiles_cull(cache, path.dentry, args);
 579         cachefiles_end_secure(cache, saved_cred);
 580 
 581         path_put(&path);
 582         _leave(" = %d", ret);
 583         return ret;
 584 
 585 notdir:
 586         path_put(&path);
 587         pr_err("cull command requires dirfd to be a directory\n");
 588         return -ENOTDIR;
 589 
 590 inval:
 591         pr_err("cull command requires dirfd and filename\n");
 592         return -EINVAL;
 593 }
 594 
 595 /*
 596  * set debugging mode
 597  * - command: "debug <mask>"
 598  */
 599 static int cachefiles_daemon_debug(struct cachefiles_cache *cache, char *args)
 600 {
 601         unsigned long mask;
 602 
 603         _enter(",%s", args);
 604 
 605         mask = simple_strtoul(args, &args, 0);
 606         if (args[0] != '\0')
 607                 goto inval;
 608 
 609         cachefiles_debug = mask;
 610         _leave(" = 0");
 611         return 0;
 612 
 613 inval:
 614         pr_err("debug command requires mask\n");
 615         return -EINVAL;
 616 }
 617 
 618 /*
 619  * find out whether an object in the current working directory is in use or not
 620  * - command: "inuse <name>"
 621  */
 622 static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args)
 623 {
 624         struct path path;
 625         const struct cred *saved_cred;
 626         int ret;
 627 
 628         //_enter(",%s", args);
 629 
 630         if (strchr(args, '/'))
 631                 goto inval;
 632 
 633         if (!test_bit(CACHEFILES_READY, &cache->flags)) {
 634                 pr_err("inuse applied to unready cache\n");
 635                 return -EIO;
 636         }
 637 
 638         if (test_bit(CACHEFILES_DEAD, &cache->flags)) {
 639                 pr_err("inuse applied to dead cache\n");
 640                 return -EIO;
 641         }
 642 
 643         /* extract the directory dentry from the cwd */
 644         get_fs_pwd(current->fs, &path);
 645 
 646         if (!d_can_lookup(path.dentry))
 647                 goto notdir;
 648 
 649         cachefiles_begin_secure(cache, &saved_cred);
 650         ret = cachefiles_check_in_use(cache, path.dentry, args);
 651         cachefiles_end_secure(cache, saved_cred);
 652 
 653         path_put(&path);
 654         //_leave(" = %d", ret);
 655         return ret;
 656 
 657 notdir:
 658         path_put(&path);
 659         pr_err("inuse command requires dirfd to be a directory\n");
 660         return -ENOTDIR;
 661 
 662 inval:
 663         pr_err("inuse command requires dirfd and filename\n");
 664         return -EINVAL;
 665 }
 666 
 667 /*
 668  * see if we have space for a number of pages and/or a number of files in the
 669  * cache
 670  */
 671 int cachefiles_has_space(struct cachefiles_cache *cache,
 672                          unsigned fnr, unsigned bnr)
 673 {
 674         struct kstatfs stats;
 675         struct path path = {
 676                 .mnt    = cache->mnt,
 677                 .dentry = cache->mnt->mnt_root,
 678         };
 679         int ret;
 680 
 681         //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u",
 682         //       (unsigned long long) cache->frun,
 683         //       (unsigned long long) cache->fcull,
 684         //       (unsigned long long) cache->fstop,
 685         //       (unsigned long long) cache->brun,
 686         //       (unsigned long long) cache->bcull,
 687         //       (unsigned long long) cache->bstop,
 688         //       fnr, bnr);
 689 
 690         /* find out how many pages of blockdev are available */
 691         memset(&stats, 0, sizeof(stats));
 692 
 693         ret = vfs_statfs(&path, &stats);
 694         if (ret < 0) {
 695                 if (ret == -EIO)
 696                         cachefiles_io_error(cache, "statfs failed");
 697                 _leave(" = %d", ret);
 698                 return ret;
 699         }
 700 
 701         stats.f_bavail >>= cache->bshift;
 702 
 703         //_debug("avail %llu,%llu",
 704         //       (unsigned long long) stats.f_ffree,
 705         //       (unsigned long long) stats.f_bavail);
 706 
 707         /* see if there is sufficient space */
 708         if (stats.f_ffree > fnr)
 709                 stats.f_ffree -= fnr;
 710         else
 711                 stats.f_ffree = 0;
 712 
 713         if (stats.f_bavail > bnr)
 714                 stats.f_bavail -= bnr;
 715         else
 716                 stats.f_bavail = 0;
 717 
 718         ret = -ENOBUFS;
 719         if (stats.f_ffree < cache->fstop ||
 720             stats.f_bavail < cache->bstop)
 721                 goto begin_cull;
 722 
 723         ret = 0;
 724         if (stats.f_ffree < cache->fcull ||
 725             stats.f_bavail < cache->bcull)
 726                 goto begin_cull;
 727 
 728         if (test_bit(CACHEFILES_CULLING, &cache->flags) &&
 729             stats.f_ffree >= cache->frun &&
 730             stats.f_bavail >= cache->brun &&
 731             test_and_clear_bit(CACHEFILES_CULLING, &cache->flags)
 732             ) {
 733                 _debug("cease culling");
 734                 cachefiles_state_changed(cache);
 735         }
 736 
 737         //_leave(" = 0");
 738         return 0;
 739 
 740 begin_cull:
 741         if (!test_and_set_bit(CACHEFILES_CULLING, &cache->flags)) {
 742                 _debug("### CULL CACHE ###");
 743                 cachefiles_state_changed(cache);
 744         }
 745 
 746         _leave(" = %d", ret);
 747         return ret;
 748 }

/* [<][>][^][v][top][bottom][index][help] */