Commit be5e6616 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull more vfs updates from Al Viro:
 "Assorted stuff from this cycle.  The big ones here are multilayer
  overlayfs from Miklos and beginning of sorting ->d_inode accesses out
  from David"

* 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (51 commits)
  autofs4 copy_dev_ioctl(): keep the value of ->size we'd used for allocation
  procfs: fix race between symlink removals and traversals
  debugfs: leave freeing a symlink body until inode eviction
  Documentation/filesystems/Locking: ->get_sb() is long gone
  trylock_super(): replacement for grab_super_passive()
  fanotify: Fix up scripted S_ISDIR/S_ISREG/S_ISLNK conversions
  Cachefiles: Fix up scripted S_ISDIR/S_ISREG/S_ISLNK conversions
  VFS: (Scripted) Convert S_ISLNK/DIR/REG(dentry->d_inode) to d_is_*(dentry)
  SELinux: Use d_is_positive() rather than testing dentry->d_inode
  Smack: Use d_is_positive() rather than testing dentry->d_inode
  TOMOYO: Use d_is_dir() rather than d_inode and S_ISDIR()
  Apparmor: Use d_is_positive/negative() rather than testing dentry->d_inode
  Apparmor: mediated_filesystem() should use dentry->d_sb not inode->i_sb
  VFS: Split DCACHE_FILE_TYPE into regular and special types
  VFS: Add a fallthrough flag for marking virtual dentries
  VFS: Add a whiteout dentry type
  VFS: Introduce inode-getting helpers for layered/unioned fs environments
  Infiniband: Fix potential NULL d_inode dereference
  posix_acl: fix reference leaks in posix_acl_create
  autofs4: Wrong format for printing dentry
  ...
parents 90c453ca 0a280962
......@@ -164,8 +164,6 @@ the block device inode. See there for more details.
--------------------------- file_system_type ---------------------------
prototypes:
int (*get_sb) (struct file_system_type *, int,
const char *, void *, struct vfsmount *);
struct dentry *(*mount) (struct file_system_type *, int,
const char *, void *);
void (*kill_sb) (struct super_block *);
......
......@@ -159,6 +159,22 @@ overlay filesystem (though an operation on the name of the file such as
rename or unlink will of course be noticed and handled).
Multiple lower layers
---------------------
Multiple lower layers can now be given using the the colon (":") as a
separator character between the directory names. For example:
mount -t overlay overlay -olowerdir=/lower1:/lower2:/lower3 /merged
As the example shows, "upperdir=" and "workdir=" may be omitted. In
that case the overlay will be read-only.
The specified lower directories will be stacked beginning from the
rightmost one and going left. In the above example lower1 will be the
top, lower2 the middle and lower3 the bottom layer.
Non-standard behavior
---------------------
......@@ -196,3 +212,15 @@ Changes to the underlying filesystems while part of a mounted overlay
filesystem are not allowed. If the underlying filesystem is changed,
the behavior of the overlay is undefined, though it will not result in
a crash or deadlock.
Testsuite
---------
There's testsuite developed by David Howells at:
git://git.infradead.org/users/dhowells/unionmount-testsuite.git
Run as root:
# cd unionmount-testsuite
# ./run --ov
......@@ -74,7 +74,7 @@ static void hypfs_remove(struct dentry *dentry)
parent = dentry->d_parent;
mutex_lock(&parent->d_inode->i_mutex);
if (hypfs_positive(dentry)) {
if (S_ISDIR(dentry->d_inode->i_mode))
if (d_is_dir(dentry))
simple_rmdir(parent->d_inode, dentry);
else
simple_unlink(parent->d_inode, dentry);
......@@ -144,36 +144,32 @@ static int hypfs_open(struct inode *inode, struct file *filp)
return nonseekable_open(inode, filp);
}
static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t offset)
static ssize_t hypfs_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
char *data;
ssize_t ret;
struct file *filp = iocb->ki_filp;
/* XXX: temporary */
char __user *buf = iov[0].iov_base;
size_t count = iov[0].iov_len;
if (nr_segs != 1)
return -EINVAL;
data = filp->private_data;
ret = simple_read_from_buffer(buf, count, &offset, data, strlen(data));
if (ret <= 0)
return ret;
struct file *file = iocb->ki_filp;
char *data = file->private_data;
size_t available = strlen(data);
loff_t pos = iocb->ki_pos;
size_t count;
iocb->ki_pos += ret;
file_accessed(filp);
return ret;
if (pos < 0)
return -EINVAL;
if (pos >= available || !iov_iter_count(to))
return 0;
count = copy_to_iter(data + pos, available - pos, to);
if (!count)
return -EFAULT;
iocb->ki_pos = pos + count;
file_accessed(file);
return count;
}
static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t offset)
static ssize_t hypfs_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
int rc;
struct super_block *sb = file_inode(iocb->ki_filp)->i_sb;
struct hypfs_sb_info *fs_info = sb->s_fs_info;
size_t count = iov_length(iov, nr_segs);
size_t count = iov_iter_count(from);
/*
* Currently we only allow one update per second for two reasons:
......@@ -202,6 +198,7 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
}
hypfs_update_update(sb);
rc = count;
iov_iter_advance(from, count);
out:
mutex_unlock(&fs_info->lock);
return rc;
......@@ -440,10 +437,10 @@ struct dentry *hypfs_create_str(struct dentry *dir,
static const struct file_operations hypfs_file_ops = {
.open = hypfs_open,
.release = hypfs_release,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = hypfs_aio_read,
.aio_write = hypfs_aio_write,
.read = new_sync_read,
.write = new_sync_write,
.read_iter = hypfs_read_iter,
.write_iter = hypfs_write_iter,
.llseek = no_llseek,
};
......
......@@ -277,7 +277,7 @@ static int remove_file(struct dentry *parent, char *name)
}
spin_lock(&tmp->d_lock);
if (!(d_unhashed(tmp) && tmp->d_inode)) {
if (!d_unhashed(tmp) && tmp->d_inode) {
dget_dlock(tmp);
__d_drop(tmp);
spin_unlock(&tmp->d_lock);
......
......@@ -455,7 +455,7 @@ static int remove_file(struct dentry *parent, char *name)
}
spin_lock(&tmp->d_lock);
if (!(d_unhashed(tmp) && tmp->d_inode)) {
if (!d_unhashed(tmp) && tmp->d_inode) {
__d_drop(tmp);
spin_unlock(&tmp->d_lock);
simple_unlink(parent->d_inode, tmp);
......
......@@ -270,7 +270,7 @@ void ll_invalidate_aliases(struct inode *inode)
int ll_revalidate_it_finish(struct ptlrpc_request *request,
struct lookup_intent *it,
struct dentry *de)
struct inode *inode)
{
int rc = 0;
......@@ -280,19 +280,17 @@ int ll_revalidate_it_finish(struct ptlrpc_request *request,
if (it_disposition(it, DISP_LOOKUP_NEG))
return -ENOENT;
rc = ll_prep_inode(&de->d_inode, request, NULL, it);
rc = ll_prep_inode(&inode, request, NULL, it);
return rc;
}
void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry)
void ll_lookup_finish_locks(struct lookup_intent *it, struct inode *inode)
{
LASSERT(it != NULL);
LASSERT(dentry != NULL);
if (it->d.lustre.it_lock_mode && dentry->d_inode != NULL) {
struct inode *inode = dentry->d_inode;
struct ll_sb_info *sbi = ll_i2sbi(dentry->d_inode);
if (it->d.lustre.it_lock_mode && inode != NULL) {
struct ll_sb_info *sbi = ll_i2sbi(inode);
CDEBUG(D_DLMTRACE, "setting l_data to inode %p (%lu/%u)\n",
inode, inode->i_ino, inode->i_generation);
......
......@@ -2912,8 +2912,8 @@ static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits)
oit.it_op = IT_LOOKUP;
/* Call getattr by fid, so do not provide name at all. */
op_data = ll_prep_md_op_data(NULL, dentry->d_inode,
dentry->d_inode, NULL, 0, 0,
op_data = ll_prep_md_op_data(NULL, inode,
inode, NULL, 0, 0,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
return PTR_ERR(op_data);
......@@ -2931,7 +2931,7 @@ static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits)
goto out;
}
rc = ll_revalidate_it_finish(req, &oit, dentry);
rc = ll_revalidate_it_finish(req, &oit, inode);
if (rc != 0) {
ll_intent_release(&oit);
goto out;
......@@ -2944,7 +2944,7 @@ static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits)
if (!dentry->d_inode->i_nlink)
d_lustre_invalidate(dentry, 0);
ll_lookup_finish_locks(&oit, dentry);
ll_lookup_finish_locks(&oit, inode);
} else if (!ll_have_md_lock(dentry->d_inode, &ibits, LCK_MINMODE)) {
struct ll_sb_info *sbi = ll_i2sbi(dentry->d_inode);
u64 valid = OBD_MD_FLGETATTR;
......
......@@ -786,9 +786,9 @@ extern const struct dentry_operations ll_d_ops;
void ll_intent_drop_lock(struct lookup_intent *);
void ll_intent_release(struct lookup_intent *);
void ll_invalidate_aliases(struct inode *);
void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry);
void ll_lookup_finish_locks(struct lookup_intent *it, struct inode *inode);
int ll_revalidate_it_finish(struct ptlrpc_request *request,
struct lookup_intent *it, struct dentry *de);
struct lookup_intent *it, struct inode *inode);
/* llite/llite_lib.c */
extern struct super_operations lustre_super_operations;
......
......@@ -481,6 +481,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
struct dentry *save = dentry, *retval;
struct ptlrpc_request *req = NULL;
struct inode *inode;
struct md_op_data *op_data;
__u32 opc;
int rc;
......@@ -539,12 +540,13 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
goto out;
}
if ((it->it_op & IT_OPEN) && dentry->d_inode &&
!S_ISREG(dentry->d_inode->i_mode) &&
!S_ISDIR(dentry->d_inode->i_mode)) {
ll_release_openhandle(dentry->d_inode, it);
inode = dentry->d_inode;
if ((it->it_op & IT_OPEN) && inode &&
!S_ISREG(inode->i_mode) &&
!S_ISDIR(inode->i_mode)) {
ll_release_openhandle(inode, it);
}
ll_lookup_finish_locks(it, dentry);
ll_lookup_finish_locks(it, inode);
if (dentry == save)
retval = NULL;
......
......@@ -1127,7 +1127,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
}
/* Write all dirty data */
if (S_ISREG(dentry->d_inode->i_mode))
if (d_is_reg(dentry))
filemap_write_and_wait(dentry->d_inode->i_mapping);
retval = p9_client_wstat(fid, &wstat);
......
......@@ -1285,7 +1285,7 @@ SYSCALL_DEFINE2(io_setup, unsigned, nr_events, aio_context_t __user *, ctxp)
ret = -EINVAL;
if (unlikely(ctx || nr_events == 0)) {
pr_debug("EINVAL: io_setup: ctx %lu nr_events %u\n",
pr_debug("EINVAL: ctx %lu nr_events %u\n",
ctx, nr_events);
goto out;
}
......@@ -1333,7 +1333,7 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
return ret;
}
pr_debug("EINVAL: io_destroy: invalid context id\n");
pr_debug("EINVAL: invalid context id\n");
return -EINVAL;
}
......@@ -1515,7 +1515,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
(iocb->aio_nbytes != (size_t)iocb->aio_nbytes) ||
((ssize_t)iocb->aio_nbytes < 0)
)) {
pr_debug("EINVAL: io_submit: overflow check\n");
pr_debug("EINVAL: overflow check\n");
return -EINVAL;
}
......
......@@ -95,7 +95,7 @@ static int check_dev_ioctl_version(int cmd, struct autofs_dev_ioctl *param)
*/
static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *in)
{
struct autofs_dev_ioctl tmp;
struct autofs_dev_ioctl tmp, *res;
if (copy_from_user(&tmp, in, sizeof(tmp)))
return ERR_PTR(-EFAULT);
......@@ -106,7 +106,11 @@ static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *i
if (tmp.size > (PATH_MAX + sizeof(tmp)))
return ERR_PTR(-ENAMETOOLONG);
return memdup_user(in, tmp.size);
res = memdup_user(in, tmp.size);
if (!IS_ERR(res))
res->size = tmp.size;
return res;
}
static inline void free_dev_ioctl(struct autofs_dev_ioctl *param)
......
......@@ -374,7 +374,7 @@ static struct dentry *should_expire(struct dentry *dentry,
return NULL;
}
if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) {
if (dentry->d_inode && d_is_symlink(dentry)) {
DPRINTK("checking symlink %p %pd", dentry, dentry);
/*
* A symlink can't be "busy" in the usual sense so
......
......@@ -108,7 +108,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
struct dentry *dentry = file->f_path.dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
DPRINTK("file=%p dentry=%p %pD", file, dentry, dentry);
DPRINTK("file=%p dentry=%p %pd", file, dentry, dentry);
if (autofs4_oz_mode(sbi))
goto out;
......@@ -371,7 +371,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
* having d_mountpoint() true, so there's no need to call back
* to the daemon.
*/
if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) {
if (dentry->d_inode && d_is_symlink(dentry)) {
spin_unlock(&sbi->fs_lock);
goto done;
}
......@@ -485,7 +485,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
* an incorrect ELOOP error return.
*/
if ((!d_mountpoint(dentry) && !simple_empty(dentry)) ||
(dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)))
(dentry->d_inode && d_is_symlink(dentry)))
status = -EISDIR;
}
spin_unlock(&sbi->fs_lock);
......
......@@ -15,161 +15,14 @@
#include <linux/namei.h>
#include <linux/poll.h>
static loff_t bad_file_llseek(struct file *file, loff_t offset, int whence)
{
return -EIO;
}
static ssize_t bad_file_read(struct file *filp, char __user *buf,
size_t size, loff_t *ppos)
{
return -EIO;
}
static ssize_t bad_file_write(struct file *filp, const char __user *buf,
size_t siz, loff_t *ppos)
{
return -EIO;
}
static ssize_t bad_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
return -EIO;
}
static ssize_t bad_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
return -EIO;
}
static int bad_file_readdir(struct file *file, struct dir_context *ctx)
{
return -EIO;
}
static unsigned int bad_file_poll(struct file *filp, poll_table *wait)
{
return POLLERR;
}
static long bad_file_unlocked_ioctl(struct file *file, unsigned cmd,
unsigned long arg)
{
return -EIO;
}
static long bad_file_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return -EIO;
}
static int bad_file_mmap(struct file *file, struct vm_area_struct *vma)
{
return -EIO;
}
static int bad_file_open(struct inode *inode, struct file *filp)
{
return -EIO;
}
static int bad_file_flush(struct file *file, fl_owner_t id)
{
return -EIO;
}
static int bad_file_release(struct inode *inode, struct file *filp)
{
return -EIO;
}
static int bad_file_fsync(struct file *file, loff_t start, loff_t end,
int datasync)
{
return -EIO;
}
static int bad_file_aio_fsync(struct kiocb *iocb, int datasync)
{
return -EIO;
}
static int bad_file_fasync(int fd, struct file *filp, int on)
{
return -EIO;
}
static int bad_file_lock(struct file *file, int cmd, struct file_lock *fl)
{
return -EIO;
}
static ssize_t bad_file_sendpage(struct file *file, struct page *page,
int off, size_t len, loff_t *pos, int more)
{
return -EIO;
}
static unsigned long bad_file_get_unmapped_area(struct file *file,
unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags)
{
return -EIO;
}
static int bad_file_check_flags(int flags)
{
return -EIO;
}
static int bad_file_flock(struct file *filp, int cmd, struct file_lock *fl)
{
return -EIO;
}
static ssize_t bad_file_splice_write(struct pipe_inode_info *pipe,
struct file *out, loff_t *ppos, size_t len,
unsigned int flags)
{
return -EIO;
}
static ssize_t bad_file_splice_read(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
return -EIO;
}
static const struct file_operations bad_file_ops =
{
.llseek = bad_file_llseek,
.read = bad_file_read,
.write = bad_file_write,
.aio_read = bad_file_aio_read,
.aio_write = bad_file_aio_write,
.iterate = bad_file_readdir,
.poll = bad_file_poll,
.unlocked_ioctl = bad_file_unlocked_ioctl,
.compat_ioctl = bad_file_compat_ioctl,
.mmap = bad_file_mmap,
.open = bad_file_open,
.flush = bad_file_flush,
.release = bad_file_release,
.fsync = bad_file_fsync,
.aio_fsync = bad_file_aio_fsync,
.fasync = bad_file_fasync,
.lock = bad_file_lock,
.sendpage = bad_file_sendpage,
.get_unmapped_area = bad_file_get_unmapped_area,
.check_flags = bad_file_check_flags,
.flock = bad_file_flock,
.splice_write = bad_file_splice_write,
.splice_read = bad_file_splice_read,
};
static int bad_inode_create (struct inode *dir, struct dentry *dentry,
......
......@@ -776,11 +776,11 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode))
return -EPERM;
if (isdir) {
if (!S_ISDIR(victim->d_inode->i_mode))
if (!d_is_dir(victim))
return -ENOTDIR;
if (IS_ROOT(victim))
return -EBUSY;
} else if (S_ISDIR(victim->d_inode->i_mode))
} else if (d_is_dir(victim))
return -EISDIR;
if (IS_DEADDIR(dir))
return -ENOENT;
......
......@@ -574,7 +574,7 @@ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args)
/* extract the directory dentry from the cwd */
get_fs_pwd(current->fs, &path);
if (!S_ISDIR(path.dentry->d_inode->i_mode))
if (!d_can_lookup(path.dentry))
goto notdir;
cachefiles_begin_secure(cache, &saved_cred);
......@@ -646,7 +646,7 @@ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args)
/* extract the directory dentry from the cwd */
get_fs_pwd(current->fs, &path);
if (!S_ISDIR(path.dentry->d_inode->i_mode))
if (!d_can_lookup(path.dentry))
goto notdir;
cachefiles_begin_secure(cache, &saved_cred);
......
......@@ -437,7 +437,7 @@ static int cachefiles_attr_changed(struct fscache_object *_object)
if (!object->backer)
return -ENOBUFS;
ASSERT(S_ISREG(object->backer->d_inode->i_mode));
ASSERT(d_is_reg(object->backer));
fscache_set_store_limit(&object->fscache, ni_size);
......@@ -501,7 +501,7 @@ static void cachefiles_invalidate_object(struct fscache_operation *op)
op->object->debug_id, (unsigned long long)ni_size);
if (object->backer) {
ASSERT(S_ISREG(object->backer->d_inode->i_mode));
ASSERT(d_is_reg(object->backer));
fscache_set_store_limit(&object->fscache, ni_size);
......
......@@ -277,7 +277,7 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
_debug("remove %p from %p", rep, dir);
/* non-directories can just be unlinked */
if (!S_ISDIR(rep->d_inode->i_mode)) {
if (!d_is_dir(rep)) {
_debug("unlink stale object");
path.mnt = cache->mnt;
......@@ -323,7 +323,7 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
return 0;
}
if (!S_ISDIR(cache->graveyard->d_inode->i_mode)) {
if (!d_can_lookup(cache->graveyard)) {
unlock_rename(cache->graveyard, dir);
cachefiles_io_error(cache, "Graveyard no longer a directory");
return -EIO;
......@@ -475,7 +475,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
ASSERT(parent->dentry);
ASSERT(parent->dentry->d_inode);
if (!(S_ISDIR(parent->dentry->d_inode->i_mode))) {
if (!(d_is_dir(parent->dentry))) {
// TODO: convert file to dir
_leave("looking up in none directory");
return -ENOBUFS;
......@@ -539,7 +539,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
_debug("mkdir -> %p{%p{ino=%lu}}",
next, next->d_inode, next->d_inode->i_ino);
} else if (!S_ISDIR(next->d_inode->i_mode)) {
} else if (!d_can_lookup(next)) {
pr_err("inode %lu is not a directory\n",
next->d_inode->i_ino);
ret = -ENOBUFS;
......@@ -568,8 +568,8 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
_debug("create -> %p{%p{ino=%lu}}",
next, next->d_inode, next->d_inode->i_ino);
} else if (!S_ISDIR(next->d_inode->i_mode) &&
!S_ISREG(next->d_inode->i_mode)
} else if (!d_can_lookup(next) &&
!d_is_reg(next)
) {
pr_err("inode %lu is not a file or directory\n",
next->d_inode->i_ino);
......@@ -642,7 +642,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
/* open a file interface onto a data file */
if (object->type != FSCACHE_COOKIE_TYPE_INDEX) {
if (S_ISREG(object->dentry->d_inode->i_mode)) {
if (d_is_reg(object->dentry)) {
const struct address_space_operations *aops;
ret = -EPERM;
......@@ -763,7 +763,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
/* we need to make sure the subdir is a directory */
ASSERT(subdir->d_inode);
if (!S_ISDIR(subdir->d_inode->i_mode)) {
if (!d_can_lookup(subdir)) {
pr_err("%s is not a directory\n", dirname);
ret = -EIO;
goto check_error;
......
......@@ -900,7 +900,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
return -ENOBUFS;
}
ASSERT(S_ISREG(object->backer->d_inode->i_mode));
ASSERT(d_is_reg(object->backer));
cache = container_of(object->fscache.cache,
struct cachefiles_cache, cache);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment