X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=fs%2Fopen.c;h=3b69c53e18379801e9bad4111e689be2cdaf1952;hb=65d3a68af53523d4d6daeb896c93e326cf46fd85;hp=be6a457f4226374b9d462cd8ee4332326ea22097;hpb=1f1c2881f673671539b25686df463518d69c4649;p=linux-2.6-omap-h63xx.git diff --git a/fs/open.c b/fs/open.c index be6a457f422..3b69c53e183 100644 --- a/fs/open.c +++ b/fs/open.c @@ -26,6 +26,7 @@ #include #include #include +#include int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) { @@ -255,24 +256,26 @@ static long do_sys_truncate(const char __user * path, loff_t length) if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; - /* - * Make sure that there are no leases. - */ - error = break_lease(inode, FMODE_WRITE); + error = get_write_access(inode); if (error) goto dput_and_out; - error = get_write_access(inode); + /* + * Make sure that there are no leases. get_write_access() protects + * against the truncate racing with a lease-granting setlease(). + */ + error = break_lease(inode, FMODE_WRITE); if (error) - goto dput_and_out; + goto put_write_and_out; error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); error = do_truncate(nd.dentry, length, 0, NULL); } - put_write_access(inode); +put_write_and_out: + put_write_access(inode); dput_and_out: path_release(&nd); out: @@ -352,6 +355,64 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length) } #endif +asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len) +{ + struct file *file; + struct inode *inode; + long ret = -EINVAL; + + if (offset < 0 || len <= 0) + goto out; + + /* Return error if mode is not supported */ + ret = -EOPNOTSUPP; + if (mode && !(mode & FALLOC_FL_KEEP_SIZE)) + goto out; + + ret = -EBADF; + file = fget(fd); + if (!file) + goto out; + if (!(file->f_mode & FMODE_WRITE)) + goto out_fput; + /* + * Revalidate the write permissions, in case security policy has + * changed since the files were opened. + */ + ret = security_file_permission(file, MAY_WRITE); + if (ret) + goto out_fput; + + inode = file->f_path.dentry->d_inode; + + ret = -ESPIPE; + if (S_ISFIFO(inode->i_mode)) + goto out_fput; + + ret = -ENODEV; + /* + * Let individual file system decide if it supports preallocation + * for directories or not. + */ + if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) + goto out_fput; + + ret = -EFBIG; + /* Check for wrap through zero too */ + if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) + goto out_fput; + + if (inode->i_op && inode->i_op->fallocate) + ret = inode->i_op->fallocate(inode, mode, offset, len); + else + ret = -EOPNOTSUPP; + +out_fput: + fput(file); +out: + return ret; +} + /* * access() needs to use the real uid/gid, not the effective uid/gid. * We do this by temporarily clearing all FS-related capabilities and @@ -508,7 +569,7 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) dentry = file->f_path.dentry; inode = dentry->d_inode; - audit_inode(NULL, inode); + audit_inode(NULL, dentry); err = -EROFS; if (IS_RDONLY(inode)) @@ -597,7 +658,8 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) newattrs.ia_gid = group; } if (!S_ISDIR(inode->i_mode)) - newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID; + newattrs.ia_valid |= + ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; mutex_lock(&inode->i_mutex); error = notify_change(dentry, &newattrs); mutex_unlock(&inode->i_mutex); @@ -665,7 +727,7 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) goto out; dentry = file->f_path.dentry; - audit_inode(NULL, dentry->d_inode); + audit_inode(NULL, dentry); error = chown_common(dentry, user, group); fput(file); out: @@ -696,6 +758,10 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); + error = security_dentry_open(f); + if (error) + goto cleanup_all; + if (!open && f->f_op) open = f->f_op->open; if (open) { @@ -1112,7 +1178,7 @@ asmlinkage long sys_vhangup(void) int generic_file_open(struct inode * inode, struct file * filp) { if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) - return -EFBIG; + return -EOVERFLOW; return 0; }