mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 22:02:02 +00:00
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs updates from Miklos Szeredi: "This update contains fixes to the "use mounter's permission to access underlying layers" area, and miscellaneous other fixes and cleanups. No new features this time" * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: use vfs_get_link() vfs: add vfs_get_link() helper ovl: use generic_readlink ovl: explain error values when removing acl from workdir ovl: Fix info leak in ovl_lookup_temp() ovl: during copy up, switch to mounter's creds early ovl: lookup: do getxattr with mounter's permission ovl: copy_up_xattr(): use strnlen
This commit is contained in:
commit
1a892b485f
6 changed files with 82 additions and 93 deletions
25
fs/namei.c
25
fs/namei.c
|
@ -4668,6 +4668,31 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(generic_readlink);
|
EXPORT_SYMBOL(generic_readlink);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vfs_get_link - get symlink body
|
||||||
|
* @dentry: dentry on which to get symbolic link
|
||||||
|
* @done: caller needs to free returned data with this
|
||||||
|
*
|
||||||
|
* Calls security hook and i_op->get_link() on the supplied inode.
|
||||||
|
*
|
||||||
|
* It does not touch atime. That's up to the caller if necessary.
|
||||||
|
*
|
||||||
|
* Does not work on "special" symlinks like /proc/$$/fd/N
|
||||||
|
*/
|
||||||
|
const char *vfs_get_link(struct dentry *dentry, struct delayed_call *done)
|
||||||
|
{
|
||||||
|
const char *res = ERR_PTR(-EINVAL);
|
||||||
|
struct inode *inode = d_inode(dentry);
|
||||||
|
|
||||||
|
if (d_is_symlink(dentry)) {
|
||||||
|
res = ERR_PTR(security_inode_readlink(dentry));
|
||||||
|
if (!res)
|
||||||
|
res = inode->i_op->get_link(dentry, inode, done);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(vfs_get_link);
|
||||||
|
|
||||||
/* get the link contents into pagecache */
|
/* get the link contents into pagecache */
|
||||||
const char *page_get_link(struct dentry *dentry, struct inode *inode,
|
const char *page_get_link(struct dentry *dentry, struct inode *inode,
|
||||||
struct delayed_call *callback)
|
struct delayed_call *callback)
|
||||||
|
|
|
@ -57,6 +57,7 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
|
||||||
ssize_t list_size, size, value_size = 0;
|
ssize_t list_size, size, value_size = 0;
|
||||||
char *buf, *name, *value = NULL;
|
char *buf, *name, *value = NULL;
|
||||||
int uninitialized_var(error);
|
int uninitialized_var(error);
|
||||||
|
size_t slen;
|
||||||
|
|
||||||
if (!(old->d_inode->i_opflags & IOP_XATTR) ||
|
if (!(old->d_inode->i_opflags & IOP_XATTR) ||
|
||||||
!(new->d_inode->i_opflags & IOP_XATTR))
|
!(new->d_inode->i_opflags & IOP_XATTR))
|
||||||
|
@ -79,7 +80,16 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name = buf; name < (buf + list_size); name += strlen(name) + 1) {
|
for (name = buf; list_size; name += slen) {
|
||||||
|
slen = strnlen(name, list_size) + 1;
|
||||||
|
|
||||||
|
/* underlying fs providing us with an broken xattr list? */
|
||||||
|
if (WARN_ON(slen > list_size)) {
|
||||||
|
error = -EIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list_size -= slen;
|
||||||
|
|
||||||
if (ovl_is_private_xattr(name))
|
if (ovl_is_private_xattr(name))
|
||||||
continue;
|
continue;
|
||||||
retry:
|
retry:
|
||||||
|
@ -174,40 +184,6 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *ovl_read_symlink(struct dentry *realdentry)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
char *buf;
|
|
||||||
struct inode *inode = realdentry->d_inode;
|
|
||||||
mm_segment_t old_fs;
|
|
||||||
|
|
||||||
res = -EINVAL;
|
|
||||||
if (!inode->i_op->readlink)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
res = -ENOMEM;
|
|
||||||
buf = (char *) __get_free_page(GFP_KERNEL);
|
|
||||||
if (!buf)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
old_fs = get_fs();
|
|
||||||
set_fs(get_ds());
|
|
||||||
/* The cast to a user pointer is valid due to the set_fs() */
|
|
||||||
res = inode->i_op->readlink(realdentry,
|
|
||||||
(char __user *)buf, PAGE_SIZE - 1);
|
|
||||||
set_fs(old_fs);
|
|
||||||
if (res < 0) {
|
|
||||||
free_page((unsigned long) buf);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
buf[res] = '\0';
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
|
|
||||||
err:
|
|
||||||
return ERR_PTR(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat)
|
static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat)
|
||||||
{
|
{
|
||||||
struct iattr attr = {
|
struct iattr attr = {
|
||||||
|
@ -354,19 +330,20 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
|
||||||
int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
|
int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
|
||||||
struct path *lowerpath, struct kstat *stat)
|
struct path *lowerpath, struct kstat *stat)
|
||||||
{
|
{
|
||||||
|
DEFINE_DELAYED_CALL(done);
|
||||||
struct dentry *workdir = ovl_workdir(dentry);
|
struct dentry *workdir = ovl_workdir(dentry);
|
||||||
int err;
|
int err;
|
||||||
struct kstat pstat;
|
struct kstat pstat;
|
||||||
struct path parentpath;
|
struct path parentpath;
|
||||||
|
struct dentry *lowerdentry = lowerpath->dentry;
|
||||||
struct dentry *upperdir;
|
struct dentry *upperdir;
|
||||||
struct dentry *upperdentry;
|
struct dentry *upperdentry;
|
||||||
const struct cred *old_cred;
|
const char *link = NULL;
|
||||||
char *link = NULL;
|
|
||||||
|
|
||||||
if (WARN_ON(!workdir))
|
if (WARN_ON(!workdir))
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
|
|
||||||
ovl_do_check_copy_up(lowerpath->dentry);
|
ovl_do_check_copy_up(lowerdentry);
|
||||||
|
|
||||||
ovl_path_upper(parent, &parentpath);
|
ovl_path_upper(parent, &parentpath);
|
||||||
upperdir = parentpath.dentry;
|
upperdir = parentpath.dentry;
|
||||||
|
@ -376,13 +353,11 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (S_ISLNK(stat->mode)) {
|
if (S_ISLNK(stat->mode)) {
|
||||||
link = ovl_read_symlink(lowerpath->dentry);
|
link = vfs_get_link(lowerdentry, &done);
|
||||||
if (IS_ERR(link))
|
if (IS_ERR(link))
|
||||||
return PTR_ERR(link);
|
return PTR_ERR(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
old_cred = ovl_override_creds(dentry->d_sb);
|
|
||||||
|
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
if (lock_rename(workdir, upperdir) != NULL) {
|
if (lock_rename(workdir, upperdir) != NULL) {
|
||||||
pr_err("overlayfs: failed to lock workdir+upperdir\n");
|
pr_err("overlayfs: failed to lock workdir+upperdir\n");
|
||||||
|
@ -403,19 +378,16 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
|
||||||
}
|
}
|
||||||
out_unlock:
|
out_unlock:
|
||||||
unlock_rename(workdir, upperdir);
|
unlock_rename(workdir, upperdir);
|
||||||
revert_creds(old_cred);
|
do_delayed_call(&done);
|
||||||
|
|
||||||
if (link)
|
|
||||||
free_page((unsigned long) link);
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ovl_copy_up(struct dentry *dentry)
|
int ovl_copy_up(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
int err;
|
int err = 0;
|
||||||
|
const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
|
||||||
|
|
||||||
err = 0;
|
|
||||||
while (!err) {
|
while (!err) {
|
||||||
struct dentry *next;
|
struct dentry *next;
|
||||||
struct dentry *parent;
|
struct dentry *parent;
|
||||||
|
@ -447,6 +419,7 @@ int ovl_copy_up(struct dentry *dentry)
|
||||||
dput(parent);
|
dput(parent);
|
||||||
dput(next);
|
dput(next);
|
||||||
}
|
}
|
||||||
|
revert_creds(old_cred);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/cred.h>
|
#include <linux/cred.h>
|
||||||
#include <linux/posix_acl.h>
|
#include <linux/posix_acl.h>
|
||||||
#include <linux/posix_acl_xattr.h>
|
#include <linux/posix_acl_xattr.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
#include "overlayfs.h"
|
#include "overlayfs.h"
|
||||||
|
|
||||||
void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
|
void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
|
||||||
|
@ -37,8 +38,10 @@ struct dentry *ovl_lookup_temp(struct dentry *workdir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct dentry *temp;
|
struct dentry *temp;
|
||||||
char name[20];
|
char name[20];
|
||||||
|
static atomic_t temp_id = ATOMIC_INIT(0);
|
||||||
|
|
||||||
snprintf(name, sizeof(name), "#%lx", (unsigned long) dentry);
|
/* counter is allowed to wrap, since temp dentries are ephemeral */
|
||||||
|
snprintf(name, sizeof(name), "#%x", atomic_inc_return(&temp_id));
|
||||||
|
|
||||||
temp = lookup_one_len(name, workdir, strlen(name));
|
temp = lookup_one_len(name, workdir, strlen(name));
|
||||||
if (!IS_ERR(temp) && temp->d_inode) {
|
if (!IS_ERR(temp) && temp->d_inode) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ static int ovl_copy_up_truncate(struct dentry *dentry)
|
||||||
struct dentry *parent;
|
struct dentry *parent;
|
||||||
struct kstat stat;
|
struct kstat stat;
|
||||||
struct path lowerpath;
|
struct path lowerpath;
|
||||||
|
const struct cred *old_cred;
|
||||||
|
|
||||||
parent = dget_parent(dentry);
|
parent = dget_parent(dentry);
|
||||||
err = ovl_copy_up(parent);
|
err = ovl_copy_up(parent);
|
||||||
|
@ -26,12 +27,14 @@ static int ovl_copy_up_truncate(struct dentry *dentry)
|
||||||
goto out_dput_parent;
|
goto out_dput_parent;
|
||||||
|
|
||||||
ovl_path_lower(dentry, &lowerpath);
|
ovl_path_lower(dentry, &lowerpath);
|
||||||
err = vfs_getattr(&lowerpath, &stat);
|
|
||||||
if (err)
|
|
||||||
goto out_dput_parent;
|
|
||||||
|
|
||||||
stat.size = 0;
|
old_cred = ovl_override_creds(dentry->d_sb);
|
||||||
err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
|
err = vfs_getattr(&lowerpath, &stat);
|
||||||
|
if (!err) {
|
||||||
|
stat.size = 0;
|
||||||
|
err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
|
||||||
|
}
|
||||||
|
revert_creds(old_cred);
|
||||||
|
|
||||||
out_dput_parent:
|
out_dput_parent:
|
||||||
dput(parent);
|
dput(parent);
|
||||||
|
@ -153,45 +156,18 @@ static const char *ovl_get_link(struct dentry *dentry,
|
||||||
struct inode *inode,
|
struct inode *inode,
|
||||||
struct delayed_call *done)
|
struct delayed_call *done)
|
||||||
{
|
{
|
||||||
struct dentry *realdentry;
|
|
||||||
struct inode *realinode;
|
|
||||||
const struct cred *old_cred;
|
const struct cred *old_cred;
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
return ERR_PTR(-ECHILD);
|
return ERR_PTR(-ECHILD);
|
||||||
|
|
||||||
realdentry = ovl_dentry_real(dentry);
|
|
||||||
realinode = realdentry->d_inode;
|
|
||||||
|
|
||||||
if (WARN_ON(!realinode->i_op->get_link))
|
|
||||||
return ERR_PTR(-EPERM);
|
|
||||||
|
|
||||||
old_cred = ovl_override_creds(dentry->d_sb);
|
old_cred = ovl_override_creds(dentry->d_sb);
|
||||||
p = realinode->i_op->get_link(realdentry, realinode, done);
|
p = vfs_get_link(ovl_dentry_real(dentry), done);
|
||||||
revert_creds(old_cred);
|
revert_creds(old_cred);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
|
|
||||||
{
|
|
||||||
struct path realpath;
|
|
||||||
struct inode *realinode;
|
|
||||||
const struct cred *old_cred;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
ovl_path_real(dentry, &realpath);
|
|
||||||
realinode = realpath.dentry->d_inode;
|
|
||||||
|
|
||||||
if (!realinode->i_op->readlink)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
old_cred = ovl_override_creds(dentry->d_sb);
|
|
||||||
err = realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
|
|
||||||
revert_creds(old_cred);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ovl_is_private_xattr(const char *name)
|
bool ovl_is_private_xattr(const char *name)
|
||||||
{
|
{
|
||||||
return strncmp(name, OVL_XATTR_PREFIX,
|
return strncmp(name, OVL_XATTR_PREFIX,
|
||||||
|
@ -375,7 +351,7 @@ static const struct inode_operations ovl_file_inode_operations = {
|
||||||
static const struct inode_operations ovl_symlink_inode_operations = {
|
static const struct inode_operations ovl_symlink_inode_operations = {
|
||||||
.setattr = ovl_setattr,
|
.setattr = ovl_setattr,
|
||||||
.get_link = ovl_get_link,
|
.get_link = ovl_get_link,
|
||||||
.readlink = ovl_readlink,
|
.readlink = generic_readlink,
|
||||||
.getattr = ovl_getattr,
|
.getattr = ovl_getattr,
|
||||||
.listxattr = ovl_listxattr,
|
.listxattr = ovl_listxattr,
|
||||||
.update_time = ovl_update_time,
|
.update_time = ovl_update_time,
|
||||||
|
|
|
@ -273,12 +273,11 @@ static bool ovl_is_opaquedir(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
char val;
|
char val;
|
||||||
struct inode *inode = dentry->d_inode;
|
|
||||||
|
|
||||||
if (!S_ISDIR(inode->i_mode) || !(inode->i_opflags & IOP_XATTR))
|
if (!d_is_dir(dentry))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
res = __vfs_getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1);
|
res = vfs_getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1);
|
||||||
if (res == 1 && val == 'y')
|
if (res == 1 && val == 'y')
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -419,16 +418,12 @@ static bool ovl_dentry_weird(struct dentry *dentry)
|
||||||
DCACHE_OP_COMPARE);
|
DCACHE_OP_COMPARE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct dentry *ovl_lookup_real(struct super_block *ovl_sb,
|
static inline struct dentry *ovl_lookup_real(struct dentry *dir,
|
||||||
struct dentry *dir,
|
|
||||||
const struct qstr *name)
|
const struct qstr *name)
|
||||||
{
|
{
|
||||||
const struct cred *old_cred;
|
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
|
||||||
old_cred = ovl_override_creds(ovl_sb);
|
|
||||||
dentry = lookup_one_len_unlocked(name->name, dir, name->len);
|
dentry = lookup_one_len_unlocked(name->name, dir, name->len);
|
||||||
revert_creds(old_cred);
|
|
||||||
|
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
if (PTR_ERR(dentry) == -ENOENT)
|
if (PTR_ERR(dentry) == -ENOENT)
|
||||||
|
@ -469,6 +464,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct ovl_entry *oe;
|
struct ovl_entry *oe;
|
||||||
|
const struct cred *old_cred;
|
||||||
struct ovl_entry *poe = dentry->d_parent->d_fsdata;
|
struct ovl_entry *poe = dentry->d_parent->d_fsdata;
|
||||||
struct path *stack = NULL;
|
struct path *stack = NULL;
|
||||||
struct dentry *upperdir, *upperdentry = NULL;
|
struct dentry *upperdir, *upperdentry = NULL;
|
||||||
|
@ -479,9 +475,10 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
old_cred = ovl_override_creds(dentry->d_sb);
|
||||||
upperdir = ovl_upperdentry_dereference(poe);
|
upperdir = ovl_upperdentry_dereference(poe);
|
||||||
if (upperdir) {
|
if (upperdir) {
|
||||||
this = ovl_lookup_real(dentry->d_sb, upperdir, &dentry->d_name);
|
this = ovl_lookup_real(upperdir, &dentry->d_name);
|
||||||
err = PTR_ERR(this);
|
err = PTR_ERR(this);
|
||||||
if (IS_ERR(this))
|
if (IS_ERR(this))
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -514,8 +511,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
bool opaque = false;
|
bool opaque = false;
|
||||||
struct path lowerpath = poe->lowerstack[i];
|
struct path lowerpath = poe->lowerstack[i];
|
||||||
|
|
||||||
this = ovl_lookup_real(dentry->d_sb,
|
this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name);
|
||||||
lowerpath.dentry, &dentry->d_name);
|
|
||||||
err = PTR_ERR(this);
|
err = PTR_ERR(this);
|
||||||
if (IS_ERR(this)) {
|
if (IS_ERR(this)) {
|
||||||
/*
|
/*
|
||||||
|
@ -588,6 +584,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
ovl_copyattr(realdentry->d_inode, inode);
|
ovl_copyattr(realdentry->d_inode, inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
revert_creds(old_cred);
|
||||||
oe->opaque = upperopaque;
|
oe->opaque = upperopaque;
|
||||||
oe->__upperdentry = upperdentry;
|
oe->__upperdentry = upperdentry;
|
||||||
memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
|
memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
|
||||||
|
@ -606,6 +603,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
out_put_upper:
|
out_put_upper:
|
||||||
dput(upperdentry);
|
dput(upperdentry);
|
||||||
out:
|
out:
|
||||||
|
revert_creds(old_cred);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,6 +832,19 @@ static struct dentry *ovl_workdir_create(struct vfsmount *mnt,
|
||||||
if (err)
|
if (err)
|
||||||
goto out_dput;
|
goto out_dput;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to remove POSIX ACL xattrs from workdir. We are good if:
|
||||||
|
*
|
||||||
|
* a) success (there was a POSIX ACL xattr and was removed)
|
||||||
|
* b) -ENODATA (there was no POSIX ACL xattr)
|
||||||
|
* c) -EOPNOTSUPP (POSIX ACL xattrs are not supported)
|
||||||
|
*
|
||||||
|
* There are various other error values that could effectively
|
||||||
|
* mean that the xattr doesn't exist (e.g. -ERANGE is returned
|
||||||
|
* if the xattr name is too long), but the set of filesystems
|
||||||
|
* allowed as upper are limited to "normal" ones, where checking
|
||||||
|
* for the above two errors is sufficient.
|
||||||
|
*/
|
||||||
err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_DEFAULT);
|
err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_DEFAULT);
|
||||||
if (err && err != -ENODATA && err != -EOPNOTSUPP)
|
if (err && err != -ENODATA && err != -EOPNOTSUPP)
|
||||||
goto out_dput;
|
goto out_dput;
|
||||||
|
|
|
@ -2934,6 +2934,7 @@ extern int vfs_stat(const char __user *, struct kstat *);
|
||||||
extern int vfs_lstat(const char __user *, struct kstat *);
|
extern int vfs_lstat(const char __user *, struct kstat *);
|
||||||
extern int vfs_fstat(unsigned int, struct kstat *);
|
extern int vfs_fstat(unsigned int, struct kstat *);
|
||||||
extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
|
extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
|
||||||
|
extern const char *vfs_get_link(struct dentry *, struct delayed_call *);
|
||||||
|
|
||||||
extern int __generic_block_fiemap(struct inode *inode,
|
extern int __generic_block_fiemap(struct inode *inode,
|
||||||
struct fiemap_extent_info *fieinfo,
|
struct fiemap_extent_info *fieinfo,
|
||||||
|
|
Loading…
Reference in a new issue