lkml.org 
[lkml]   [2007]   [Dec]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[AppArmor 32/47] From: Miklos Szeredi <>
    Add a new file operation: f_op->fgetattr(), that is invoked by
    fstat(). Fall back to i_op->getattr() if it is not defined.

    We need this because fstat() semantics can in some cases be better
    implemented if the filesystem has the open file available.

    Let's take the following example: we have a network filesystem, with
    the server implemented as an unprivileged userspace process running on
    a UNIX system (this is basically what sshfs does).

    We want the filesystem to follow the familiar UNIX file semantics as
    closely as possible. If for example we have this sequence of events,
    we still would like fstat to work correctly:

    1) file X is opened on client
    2) file X is renamed to Y on server
    3) fstat() is performed on open file descriptor on client

    This is only possible if the filesystem server acutally uses fstat()
    on a file descriptor obtained when the file was opened. Which means,
    the filesystem client needs a way to get this information from the
    VFS.

    Even if we assume, that the remote filesystem never changes, it is
    difficult to implement open-unlink-fstat semantics correctly in the
    client, without having this information.

    Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
    Signed-off-by: John Johansen <jjohansen@suse.de>

    ---

    ---
    fs/fuse/file.c | 13 +++++++++++++
    fs/stat.c | 29 ++++++++++++++++++++++++++++-
    include/linux/fs.h | 1 +
    3 files changed, 42 insertions(+), 1 deletion(-)

    --- a/fs/fuse/file.c
    +++ b/fs/fuse/file.c
    @@ -871,6 +871,17 @@ static int fuse_file_flock(struct file *
    return err;
    }

    +static int fuse_file_fgetattr(struct file *file, struct kstat *stat)
    +{
    + struct inode *inode = file->f_dentry->d_inode;
    + struct fuse_conn *fc = get_fuse_conn(inode);
    +
    + if (!fuse_allow_task(fc, current))
    + return -EACCES;
    +
    + return fuse_update_attributes(inode, stat, file, NULL);
    +}
    +
    static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
    {
    struct inode *inode = mapping->host;
    @@ -920,6 +931,7 @@ static const struct file_operations fuse
    .fsync = fuse_fsync,
    .lock = fuse_file_lock,
    .flock = fuse_file_flock,
    + .fgetattr = fuse_file_fgetattr,
    .splice_read = generic_file_splice_read,
    };

    @@ -933,6 +945,7 @@ static const struct file_operations fuse
    .fsync = fuse_fsync,
    .lock = fuse_file_lock,
    .flock = fuse_file_flock,
    + .fgetattr = fuse_file_fgetattr,
    /* no mmap and splice_read */
    };

    --- a/fs/stat.c
    +++ b/fs/stat.c
    @@ -55,6 +55,33 @@ int vfs_getattr(struct vfsmount *mnt, st

    EXPORT_SYMBOL(vfs_getattr);

    +/*
    + * Perform getattr on an open file
    + *
    + * Fall back to i_op->getattr (or generic_fillattr) if the filesystem
    + * doesn't define an f_op->fgetattr operation.
    + */
    +static int vfs_fgetattr(struct file *file, struct kstat *stat)
    +{
    + struct vfsmount *mnt = file->f_path.mnt;
    + struct dentry *dentry = file->f_path.dentry;
    + struct inode *inode = dentry->d_inode;
    + int retval;
    +
    + retval = security_inode_getattr(mnt, dentry);
    + if (retval)
    + return retval;
    +
    + if (file->f_op && file->f_op->fgetattr) {
    + return file->f_op->fgetattr(file, stat);
    + } else if (inode->i_op->getattr) {
    + return inode->i_op->getattr(mnt, dentry, stat);
    + } else {
    + generic_fillattr(inode, stat);
    + return 0;
    + }
    +}
    +
    int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
    {
    struct nameidata nd;
    @@ -101,7 +128,7 @@ int vfs_fstat(unsigned int fd, struct ks
    int error = -EBADF;

    if (f) {
    - error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
    + error = vfs_fgetattr(f, stat);
    fput(f);
    }
    return error;
    --- a/include/linux/fs.h
    +++ b/include/linux/fs.h
    @@ -1190,6 +1190,7 @@ struct file_operations {
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
    int (*setlease)(struct file *, long, struct file_lock **);
    + int (*fgetattr)(struct file *, struct kstat *);
    };

    struct inode_operations {
    --



    \
     
     \ /
      Last update: 2007-12-20 15:30    [W:0.029 / U:2.592 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site