X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=fs%2Fgfs2%2Fops_file.c;h=3064f133bf3c23380bbb6ee2bc5e824fdfd6dfa9;hb=abbdbd2065e74411dc2c401501c2c85a82f60e06;hp=b86037832299834bf96a679617c36ddca2b873c8;hpb=61a30dcb5866eb7e92796b2988ddb4c94b9f78ac;p=powerpc.git diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index b860378322..3064f133bf 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -1,10 +1,10 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License v.2. + * of the GNU General Public License version 2. */ #include @@ -17,12 +17,15 @@ #include #include #include -#include #include -#include +#include +#include +#include +#include #include #include "gfs2.h" +#include "incore.h" #include "bmap.h" #include "dir.h" #include "glock.h" @@ -36,27 +39,8 @@ #include "quota.h" #include "rgrp.h" #include "trans.h" - -/* "bad" is for NFS support */ -struct filldir_bad_entry { - char *fbe_name; - unsigned int fbe_length; - uint64_t fbe_offset; - struct gfs2_inum fbe_inum; - unsigned int fbe_type; -}; - -struct filldir_bad { - struct gfs2_sbd *fdb_sbd; - - struct filldir_bad_entry *fdb_entry; - unsigned int fdb_entry_num; - unsigned int fdb_entry_off; - - char *fdb_name; - unsigned int fdb_name_size; - unsigned int fdb_name_off; -}; +#include "util.h" +#include "eaops.h" /* For regular, non-NFS */ struct filldir_reg { @@ -73,7 +57,7 @@ struct filldir_reg { * any other part of this. Its use is purely as a flag so that we * know (in readpage()) whether or not do to locking. */ -struct file gfs2_internal_file_sentinal = { +struct file gfs2_internal_file_sentinel = { .f_flags = O_NOATIME|O_RDONLY, }; @@ -88,25 +72,25 @@ static int gfs2_read_actor(read_descriptor_t *desc, struct page *page, kaddr = kmap(page); memcpy(desc->arg.buf, kaddr + offset, size); - kunmap(page); + kunmap(page); - desc->count = count - size; - desc->written += size; - desc->arg.buf += size; - return size; + desc->count = count - size; + desc->written += size; + desc->arg.buf += size; + return size; } int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, char *buf, loff_t *pos, unsigned size) { - struct inode *inode = ip->i_vnode; + struct inode *inode = &ip->i_inode; read_descriptor_t desc; desc.written = 0; desc.arg.buf = buf; desc.count = size; desc.error = 0; do_generic_mapping_read(inode->i_mapping, ra_state, - &gfs2_internal_file_sentinal, pos, &desc, + &gfs2_internal_file_sentinel, pos, &desc, gfs2_read_actor); return desc.written ? desc.written : desc.error; } @@ -125,12 +109,10 @@ int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) { - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); struct gfs2_holder i_gh; loff_t error; - atomic_inc(&ip->i_sbd->sd_ops_file); - if (origin == 2) { error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); @@ -144,179 +126,8 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) return error; } - -static ssize_t gfs2_direct_IO_read(struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) -{ - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - ssize_t retval; - - retval = filemap_write_and_wait(mapping); - if (retval == 0) { - retval = mapping->a_ops->direct_IO(READ, iocb, iov, offset, - nr_segs); - } - return retval; -} - /** - * __gfs2_file_aio_read - The main GFS2 read function - * - * N.B. This is almost, but not quite the same as __generic_file_aio_read() - * the important subtle different being that inode->i_size isn't valid - * unless we are holding a lock, and we do this _only_ on the O_DIRECT - * path since otherwise locking is done entirely at the page cache - * layer. - */ -static ssize_t __gfs2_file_aio_read(struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct file *filp = iocb->ki_filp; - struct gfs2_inode *ip = get_v2ip(filp->f_mapping->host); - struct gfs2_holder gh; - ssize_t retval; - unsigned long seg; - size_t count; - - count = 0; - for (seg = 0; seg < nr_segs; seg++) { - const struct iovec *iv = &iov[seg]; - - /* - * If any segment has a negative length, or the cumulative - * length ever wraps negative then return -EINVAL. - */ - count += iv->iov_len; - if (unlikely((ssize_t)(count|iv->iov_len) < 0)) - return -EINVAL; - if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len)) - continue; - if (seg == 0) - return -EFAULT; - nr_segs = seg; - count -= iv->iov_len; /* This segment is no good */ - break; - } - - /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ - if (filp->f_flags & O_DIRECT) { - loff_t pos = *ppos, size; - struct address_space *mapping; - struct inode *inode; - - mapping = filp->f_mapping; - inode = mapping->host; - retval = 0; - if (!count) - goto out; /* skip atime */ - - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); - retval = gfs2_glock_nq_m_atime(1, &gh); - if (retval) - goto out; - if (gfs2_is_stuffed(ip)) { - gfs2_glock_dq_m(1, &gh); - gfs2_holder_uninit(&gh); - goto fallback_to_normal; - } - size = i_size_read(inode); - if (pos < size) { - retval = gfs2_direct_IO_read(iocb, iov, pos, nr_segs); - if (retval > 0 && !is_sync_kiocb(iocb)) - retval = -EIOCBQUEUED; - if (retval > 0) - *ppos = pos + retval; - } - file_accessed(filp); - gfs2_glock_dq_m(1, &gh); - gfs2_holder_uninit(&gh); - goto out; - } - -fallback_to_normal: - retval = 0; - if (count) { - for (seg = 0; seg < nr_segs; seg++) { - read_descriptor_t desc; - - desc.written = 0; - desc.arg.buf = iov[seg].iov_base; - desc.count = iov[seg].iov_len; - if (desc.count == 0) - continue; - desc.error = 0; - do_generic_file_read(filp,ppos,&desc,file_read_actor); - retval += desc.written; - if (desc.error) { - retval = retval ?: desc.error; - break; - } - } - } -out: - return retval; -} - -/** - * gfs2_read - Read bytes from a file - * @file: The file to read from - * @buf: The buffer to copy into - * @size: The amount of data requested - * @offset: The current file offset - * - * Outputs: Offset - updated according to number of bytes read - * - * Returns: The number of bytes read, errno on failure - */ - -static ssize_t gfs2_read(struct file *filp, char __user *buf, size_t size, - loff_t *offset) -{ - struct iovec local_iov = { .iov_base = buf, .iov_len = size }; - struct kiocb kiocb; - ssize_t ret; - - atomic_inc(&get_v2sdp(filp->f_mapping->host->i_sb)->sd_ops_file); - - init_sync_kiocb(&kiocb, filp); - ret = __gfs2_file_aio_read(&kiocb, &local_iov, 1, offset); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&kiocb); - return ret; -} - -static ssize_t gfs2_file_readv(struct file *filp, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct kiocb kiocb; - ssize_t ret; - - atomic_inc(&get_v2sdp(filp->f_mapping->host->i_sb)->sd_ops_file); - - init_sync_kiocb(&kiocb, filp); - ret = __gfs2_file_aio_read(&kiocb, iov, nr_segs, ppos); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&kiocb); - return ret; -} - -static ssize_t gfs2_file_aio_read(struct kiocb *iocb, char __user *buf, - size_t count, loff_t pos) -{ - struct file *filp = iocb->ki_filp; - struct iovec local_iov = { .iov_base = buf, .iov_len = count }; - - atomic_inc(&get_v2sdp(filp->f_mapping->host->i_sb)->sd_ops_file); - - BUG_ON(iocb->ki_pos != pos); - return __gfs2_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); -} - - -/** - * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() + * filldir_func - Report a directory entry to the caller of gfs2_dir_read() * @opaque: opaque data used by the function * @name: the name of the directory entry * @length: the length of the name @@ -327,25 +138,23 @@ static ssize_t gfs2_file_aio_read(struct kiocb *iocb, char __user *buf, * Returns: 0 on success, 1 if buffer full */ -static int filldir_reg_func(void *opaque, const char *name, unsigned int length, - uint64_t offset, struct gfs2_inum *inum, - unsigned int type) +static int filldir_func(void *opaque, const char *name, unsigned int length, + u64 offset, struct gfs2_inum *inum, + unsigned int type) { struct filldir_reg *fdr = (struct filldir_reg *)opaque; struct gfs2_sbd *sdp = fdr->fdr_sbd; int error; error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset, - inum->no_formal_ino, type); + inum->no_addr, type); if (error) return 1; if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) { - gfs2_glock_prefetch_num(sdp, - inum->no_addr, &gfs2_inode_glops, + gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_inode_glops, LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY); - gfs2_glock_prefetch_num(sdp, - inum->no_addr, &gfs2_iopen_glops, + gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_iopen_glops, LM_ST_SHARED, LM_FLAG_TRY); } @@ -353,7 +162,7 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, } /** - * readdir_reg - Read directory entries from a directory + * gfs2_readdir - Read directory entries from a directory * @file: The directory to read from * @dirent: Buffer for dirents * @filldir: Function used to do the copying @@ -361,15 +170,16 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, * Returns: errno */ -static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) +static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) { - struct gfs2_inode *dip = get_v2ip(file->f_mapping->host); + struct inode *dir = file->f_mapping->host; + struct gfs2_inode *dip = GFS2_I(dir); struct filldir_reg fdr; struct gfs2_holder d_gh; - uint64_t offset = file->f_pos; + u64 offset = file->f_pos; int error; - fdr.fdr_sbd = dip->i_sbd; + fdr.fdr_sbd = GFS2_SB(dir); fdr.fdr_prefetch = 1; fdr.fdr_filldir = filldir; fdr.fdr_opaque = dirent; @@ -381,7 +191,7 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) return error; } - error = gfs2_dir_read(dip, &offset, &fdr, filldir_reg_func); + error = gfs2_dir_read(dir, &offset, &fdr, filldir_func); gfs2_glock_dq_uninit(&d_gh); @@ -391,245 +201,171 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) } /** - * filldir_bad_func - Report a directory entry to the caller of gfs2_dir_read() - * @opaque: opaque data used by the function - * @name: the name of the directory entry - * @length: the length of the name - * @offset: the entry's offset in the directory - * @inum: the inode number the entry points to - * @type: the type of inode the entry points to + * fsflags_cvt + * @table: A table of 32 u32 flags + * @val: a 32 bit value to convert * - * For supporting NFS. + * This function can be used to convert between fsflags values and + * GFS2's own flags values. * - * Returns: 0 on success, 1 if buffer full + * Returns: the converted flags */ - -static int filldir_bad_func(void *opaque, const char *name, unsigned int length, - uint64_t offset, struct gfs2_inum *inum, - unsigned int type) +static u32 fsflags_cvt(const u32 *table, u32 val) { - struct filldir_bad *fdb = (struct filldir_bad *)opaque; - struct gfs2_sbd *sdp = fdb->fdb_sbd; - struct filldir_bad_entry *fbe; - - if (fdb->fdb_entry_off == fdb->fdb_entry_num || - fdb->fdb_name_off + length > fdb->fdb_name_size) - return 1; - - fbe = &fdb->fdb_entry[fdb->fdb_entry_off]; - fbe->fbe_name = fdb->fdb_name + fdb->fdb_name_off; - memcpy(fbe->fbe_name, name, length); - fbe->fbe_length = length; - fbe->fbe_offset = offset; - fbe->fbe_inum = *inum; - fbe->fbe_type = type; - - fdb->fdb_entry_off++; - fdb->fdb_name_off += length; - - if (!(length == 1 && *name == '.')) { - gfs2_glock_prefetch_num(sdp, - inum->no_addr, &gfs2_inode_glops, - LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY); - gfs2_glock_prefetch_num(sdp, - inum->no_addr, &gfs2_iopen_glops, - LM_ST_SHARED, LM_FLAG_TRY); + u32 res = 0; + while(val) { + if (val & 1) + res |= *table; + table++; + val >>= 1; } - - return 0; + return res; } -/** - * readdir_bad - Read directory entries from a directory - * @file: The directory to read from - * @dirent: Buffer for dirents - * @filldir: Function used to do the copying - * - * For supporting NFS. - * - * Returns: errno - */ +static const u32 fsflags_to_gfs2[32] = { + [3] = GFS2_DIF_SYNC, + [4] = GFS2_DIF_IMMUTABLE, + [5] = GFS2_DIF_APPENDONLY, + [7] = GFS2_DIF_NOATIME, + [12] = GFS2_DIF_EXHASH, + [14] = GFS2_DIF_JDATA, + [20] = GFS2_DIF_DIRECTIO, +}; + +static const u32 gfs2_to_fsflags[32] = { + [gfs2fl_Sync] = FS_SYNC_FL, + [gfs2fl_Immutable] = FS_IMMUTABLE_FL, + [gfs2fl_AppendOnly] = FS_APPEND_FL, + [gfs2fl_NoAtime] = FS_NOATIME_FL, + [gfs2fl_ExHash] = FS_INDEX_FL, + [gfs2fl_Jdata] = FS_JOURNAL_DATA_FL, + [gfs2fl_Directio] = FS_DIRECTIO_FL, + [gfs2fl_InheritDirectio] = FS_DIRECTIO_FL, + [gfs2fl_InheritJdata] = FS_JOURNAL_DATA_FL, +}; -static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) +static int gfs2_get_flags(struct file *filp, u32 __user *ptr) { - struct gfs2_inode *dip = get_v2ip(file->f_mapping->host); - struct gfs2_sbd *sdp = dip->i_sbd; - struct filldir_reg fdr; - unsigned int entries, size; - struct filldir_bad *fdb; - struct gfs2_holder d_gh; - uint64_t offset = file->f_pos; - unsigned int x; - struct filldir_bad_entry *fbe; + struct inode *inode = filp->f_dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_holder gh; int error; + u32 fsflags; - entries = gfs2_tune_get(sdp, gt_entries_per_readdir); - size = sizeof(struct filldir_bad) + - entries * (sizeof(struct filldir_bad_entry) + GFS2_FAST_NAME_SIZE); - - fdb = kzalloc(size, GFP_KERNEL); - if (!fdb) - return -ENOMEM; - - fdb->fdb_sbd = sdp; - fdb->fdb_entry = (struct filldir_bad_entry *)(fdb + 1); - fdb->fdb_entry_num = entries; - fdb->fdb_name = ((char *)fdb) + sizeof(struct filldir_bad) + - entries * sizeof(struct filldir_bad_entry); - fdb->fdb_name_size = entries * GFS2_FAST_NAME_SIZE; - - gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh); - error = gfs2_glock_nq_atime(&d_gh); - if (error) { - gfs2_holder_uninit(&d_gh); - goto out; - } - - error = gfs2_dir_read(dip, &offset, fdb, filldir_bad_func); - - gfs2_glock_dq_uninit(&d_gh); - - fdr.fdr_sbd = sdp; - fdr.fdr_prefetch = 0; - fdr.fdr_filldir = filldir; - fdr.fdr_opaque = dirent; - - for (x = 0; x < fdb->fdb_entry_off; x++) { - fbe = &fdb->fdb_entry[x]; - - error = filldir_reg_func(&fdr, - fbe->fbe_name, fbe->fbe_length, - fbe->fbe_offset, - &fbe->fbe_inum, fbe->fbe_type); - if (error) { - file->f_pos = fbe->fbe_offset; - error = 0; - goto out; - } - } - - file->f_pos = offset; + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); + error = gfs2_glock_nq_m_atime(1, &gh); + if (error) + return error; - out: - kfree(fdb); + fsflags = fsflags_cvt(gfs2_to_fsflags, ip->i_di.di_flags); + if (put_user(fsflags, ptr)) + error = -EFAULT; + gfs2_glock_dq_m(1, &gh); + gfs2_holder_uninit(&gh); return error; } +/* Flags that can be set by user space */ +#define GFS2_FLAGS_USER_SET (GFS2_DIF_JDATA| \ + GFS2_DIF_DIRECTIO| \ + GFS2_DIF_IMMUTABLE| \ + GFS2_DIF_APPENDONLY| \ + GFS2_DIF_NOATIME| \ + GFS2_DIF_SYNC| \ + GFS2_DIF_SYSTEM| \ + GFS2_DIF_INHERIT_DIRECTIO| \ + GFS2_DIF_INHERIT_JDATA) + /** - * gfs2_readdir - Read directory entries from a directory - * @file: The directory to read from - * @dirent: Buffer for dirents - * @filldir: Function used to do the copying + * gfs2_set_flags - set flags on an inode + * @inode: The inode + * @flags: The flags to set + * @mask: Indicates which flags are valid * - * Returns: errno */ - -static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) +static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) { + struct inode *inode = filp->f_dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + struct buffer_head *bh; + struct gfs2_holder gh; int error; + u32 new_flags, flags; - atomic_inc(&get_v2sdp(file->f_mapping->host->i_sb)->sd_ops_file); - - if (strcmp(current->comm, "nfsd") != 0) - error = readdir_reg(file, dirent, filldir); - else - error = readdir_bad(file, dirent, filldir); - - return error; -} + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + if (error) + return error; -static int gfs2_ioctl_flags(struct gfs2_inode *ip, unsigned int cmd, unsigned long arg) -{ - unsigned int lmode = (cmd == GFS2_IOCTL_SETFLAGS) ? LM_ST_EXCLUSIVE : LM_ST_SHARED; - struct buffer_head *dibh; - struct gfs2_holder i_gh; - int error; - __u32 flags = 0, change; + flags = ip->i_di.di_flags; + new_flags = (flags & ~mask) | (reqflags & mask); + if ((new_flags ^ flags) == 0) + goto out; - if (cmd == GFS2_IOCTL_SETFLAGS) { - error = get_user(flags, (__u32 __user *)arg); - if (error) - return -EFAULT; + if (S_ISDIR(inode->i_mode)) { + if ((new_flags ^ flags) & GFS2_DIF_JDATA) + new_flags ^= (GFS2_DIF_JDATA|GFS2_DIF_INHERIT_JDATA); + if ((new_flags ^ flags) & GFS2_DIF_DIRECTIO) + new_flags ^= (GFS2_DIF_DIRECTIO|GFS2_DIF_INHERIT_DIRECTIO); } - error = gfs2_glock_nq_init(ip->i_gl, lmode, 0, &i_gh); - if (error) - return error; - - if (cmd == GFS2_IOCTL_SETFLAGS) { - change = flags ^ ip->i_di.di_flags; - error = -EPERM; - if (change & (GFS2_DIF_IMMUTABLE|GFS2_DIF_APPENDONLY)) { - if (!capable(CAP_LINUX_IMMUTABLE)) - goto out; - } - error = -EINVAL; - if (flags & (GFS2_DIF_JDATA|GFS2_DIF_DIRECTIO)) { - if (!S_ISREG(ip->i_di.di_mode)) - goto out; - } - if (flags & (GFS2_DIF_INHERIT_JDATA|GFS2_DIF_INHERIT_DIRECTIO)) { - if (!S_ISDIR(ip->i_di.di_mode)) - goto out; - } + error = -EINVAL; + if ((new_flags ^ flags) & ~GFS2_FLAGS_USER_SET) + goto out; - error = gfs2_trans_begin(ip->i_sbd, RES_DINODE, 0); + error = -EPERM; + if (IS_IMMUTABLE(inode) && (new_flags & GFS2_DIF_IMMUTABLE)) + goto out; + if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY)) + goto out; + if (((new_flags ^ flags) & GFS2_DIF_IMMUTABLE) && + !capable(CAP_LINUX_IMMUTABLE)) + goto out; + if (!IS_IMMUTABLE(inode)) { + error = permission(inode, MAY_WRITE, NULL); if (error) goto out; + } - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto out_trans_end; - - ip->i_di.di_flags = flags; - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); - - brelse(dibh); - + error = gfs2_trans_begin(sdp, RES_DINODE, 0); + if (error) + goto out; + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + goto out_trans_end; + gfs2_trans_add_bh(ip->i_gl, bh, 1); + ip->i_di.di_flags = new_flags; + gfs2_dinode_out(&ip->i_di, bh->b_data); + brelse(bh); out_trans_end: - gfs2_trans_end(ip->i_sbd); - } else { - flags = ip->i_di.di_flags; - } + gfs2_trans_end(sdp); out: - gfs2_glock_dq_uninit(&i_gh); - if (cmd == GFS2_IOCTL_GETFLAGS) { - if (put_user(flags, (__u32 __user *)arg)) - return -EFAULT; - } + gfs2_glock_dq_uninit(&gh); return error; } -/** - * gfs2_ioctl - do an ioctl on a file - * @inode: the inode - * @file: the file pointer - * @cmd: the ioctl command - * @arg: the argument - * - * Returns: errno - */ - -static int gfs2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static int gfs2_set_flags(struct file *filp, u32 __user *ptr) { - struct gfs2_inode *ip = get_v2ip(inode); - - atomic_inc(&ip->i_sbd->sd_ops_file); - - switch (cmd) { - case GFS2_IOCTL_SETFLAGS: - case GFS2_IOCTL_GETFLAGS: - return gfs2_ioctl_flags(ip, cmd, arg); + u32 fsflags, gfsflags; + if (get_user(fsflags, ptr)) + return -EFAULT; + gfsflags = fsflags_cvt(fsflags_to_gfs2, fsflags); + return do_gfs2_set_flags(filp, gfsflags, ~0); +} - default: - return -ENOTTY; +static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + switch(cmd) { + case FS_IOC_GETFLAGS: + return gfs2_get_flags(filp, (u32 __user *)arg); + case FS_IOC_SETFLAGS: + return gfs2_set_flags(filp, (u32 __user *)arg); } + return -ENOTTY; } + /** * gfs2_mmap - * @file: The file to map @@ -640,12 +376,10 @@ static int gfs2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) { - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); struct gfs2_holder i_gh; int error; - atomic_inc(&ip->i_sbd->sd_ops_file); - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh); error = gfs2_glock_nq_atime(&i_gh); if (error) { @@ -677,24 +411,19 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) static int gfs2_open(struct inode *inode, struct file *file) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder i_gh; struct gfs2_file *fp; int error; - atomic_inc(&ip->i_sbd->sd_ops_file); - fp = kzalloc(sizeof(struct gfs2_file), GFP_KERNEL); if (!fp) return -ENOMEM; - init_MUTEX(&fp->f_fl_mutex); - - fp->f_inode = ip; - fp->f_vfile = file; + mutex_init(&fp->f_fl_mutex); - gfs2_assert_warn(ip->i_sbd, !get_v2fp(file)); - set_v2fp(file, fp); + gfs2_assert_warn(GFS2_SB(inode), !file->private_data); + file->private_data = fp; if (S_ISREG(ip->i_di.di_mode)) { error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, @@ -718,13 +447,11 @@ static int gfs2_open(struct inode *inode, struct file *file) return 0; - fail_gunlock: +fail_gunlock: gfs2_glock_dq_uninit(&i_gh); - - fail: - set_v2fp(file, NULL); +fail: + file->private_data = NULL; kfree(fp); - return error; } @@ -738,13 +465,11 @@ static int gfs2_open(struct inode *inode, struct file *file) static int gfs2_close(struct inode *inode, struct file *file) { - struct gfs2_sbd *sdp = get_v2sdp(inode->i_sb); + struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; struct gfs2_file *fp; - atomic_inc(&sdp->sd_ops_file); - - fp = get_v2fp(file); - set_v2fp(file, NULL); + fp = file->private_data; + file->private_data = NULL; if (gfs2_assert_warn(sdp, fp)) return -EIO; @@ -764,10 +489,9 @@ static int gfs2_close(struct inode *inode, struct file *file) static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync) { - struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + struct gfs2_inode *ip = GFS2_I(dentry->d_inode); - atomic_inc(&ip->i_sbd->sd_ops_file); - gfs2_log_flush_glock(ip->i_gl); + gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); return 0; } @@ -783,14 +507,12 @@ static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync) static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) { - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); + struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host); struct lm_lockname name = { .ln_number = ip->i_num.no_addr, .ln_type = LM_TYPE_PLOCK }; - atomic_inc(&sdp->sd_ops_file); - if (!(fl->fl_flags & FL_POSIX)) return -ENOLCK; if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID) @@ -798,20 +520,15 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) if (sdp->sd_args.ar_localflocks) { if (IS_GETLK(cmd)) { - struct file_lock *tmp; - lock_kernel(); - tmp = posix_test_lock(file, fl); + struct file_lock tmp; + int ret; + ret = posix_test_lock(file, fl, &tmp); fl->fl_type = F_UNLCK; - if (tmp) - memcpy(fl, tmp, sizeof(struct file_lock)); - unlock_kernel(); + if (ret) + memcpy(fl, &tmp, sizeof(struct file_lock)); return 0; } else { - int error; - lock_kernel(); - error = posix_lock_file_wait(file, fl); - unlock_kernel(); - return error; + return posix_lock_file_wait(file, fl); } } @@ -823,42 +540,20 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) return gfs2_lm_plock(sdp, &name, file, cmd, fl); } -/** - * gfs2_sendfile - Send bytes to a file or socket - * @in_file: The file to read from - * @out_file: The file to write to - * @count: The amount of data - * @offset: The beginning file offset - * - * Outputs: offset - updated according to number of bytes read - * - * Returns: The number of bytes sent, errno on failure - */ - -static ssize_t gfs2_sendfile(struct file *in_file, loff_t *offset, size_t count, - read_actor_t actor, void *target) -{ - struct gfs2_inode *ip = get_v2ip(in_file->f_mapping->host); - - atomic_inc(&ip->i_sbd->sd_ops_file); - - return generic_file_sendfile(in_file, offset, count, actor, target); -} - static int do_flock(struct file *file, int cmd, struct file_lock *fl) { - struct gfs2_file *fp = get_v2fp(file); + struct gfs2_file *fp = file->private_data; struct gfs2_holder *fl_gh = &fp->f_fl_gh; - struct gfs2_inode *ip = fp->f_inode; + struct gfs2_inode *ip = GFS2_I(file->f_dentry->d_inode); struct gfs2_glock *gl; unsigned int state; int flags; int error = 0; state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED; - flags = ((IS_SETLKW(cmd)) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE; + flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE; - down(&fp->f_fl_mutex); + mutex_lock(&fp->f_fl_mutex); gl = fl_gh->gh_gl; if (gl) { @@ -866,10 +561,10 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) goto out; gfs2_glock_hold(gl); flock_lock_file_wait(file, - &(struct file_lock){.fl_type = F_UNLCK}); + &(struct file_lock){.fl_type = F_UNLCK}); gfs2_glock_dq_uninit(fl_gh); } else { - error = gfs2_glock_get(ip->i_sbd, + error = gfs2_glock_get(GFS2_SB(&ip->i_inode), ip->i_num.no_addr, &gfs2_flock_glops, CREATE, &gl); if (error) @@ -886,25 +581,24 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) error = -EAGAIN; } else { error = flock_lock_file_wait(file, fl); - gfs2_assert_warn(ip->i_sbd, !error); + gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); } - out: - up(&fp->f_fl_mutex); - +out: + mutex_unlock(&fp->f_fl_mutex); return error; } static void do_unflock(struct file *file, struct file_lock *fl) { - struct gfs2_file *fp = get_v2fp(file); + struct gfs2_file *fp = file->private_data; struct gfs2_holder *fl_gh = &fp->f_fl_gh; - down(&fp->f_fl_mutex); + mutex_lock(&fp->f_fl_mutex); flock_lock_file_wait(file, fl); if (fl_gh->gh_gl) gfs2_glock_dq_uninit(fl_gh); - up(&fp->f_fl_mutex); + mutex_unlock(&fp->f_fl_mutex); } /** @@ -918,10 +612,8 @@ static void do_unflock(struct file *file, struct file_lock *fl) static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) { - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); - struct gfs2_sbd *sdp = ip->i_sbd; - - atomic_inc(&ip->i_sbd->sd_ops_file); + struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); + struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host); if (!(fl->fl_flags & FL_FLOCK)) return -ENOLCK; @@ -934,35 +626,36 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) if (fl->fl_type == F_UNLCK) { do_unflock(file, fl); return 0; - } else + } else { return do_flock(file, cmd, fl); + } } -struct file_operations gfs2_file_fops = { - .llseek = gfs2_llseek, - .read = gfs2_read, - .readv = gfs2_file_readv, - .aio_read = gfs2_file_aio_read, - .write = generic_file_write, - .writev = generic_file_writev, - .aio_write = generic_file_aio_write, - .ioctl = gfs2_ioctl, - .mmap = gfs2_mmap, - .open = gfs2_open, - .release = gfs2_close, - .fsync = gfs2_fsync, - .lock = gfs2_lock, - .sendfile = gfs2_sendfile, - .flock = gfs2_flock, +const struct file_operations gfs2_file_fops = { + .llseek = gfs2_llseek, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, + .unlocked_ioctl = gfs2_ioctl, + .mmap = gfs2_mmap, + .open = gfs2_open, + .release = gfs2_close, + .fsync = gfs2_fsync, + .lock = gfs2_lock, + .sendfile = generic_file_sendfile, + .flock = gfs2_flock, + .splice_read = generic_file_splice_read, + .splice_write = generic_file_splice_write, }; -struct file_operations gfs2_dir_fops = { - .readdir = gfs2_readdir, - .ioctl = gfs2_ioctl, - .open = gfs2_open, - .release = gfs2_close, - .fsync = gfs2_fsync, - .lock = gfs2_lock, - .flock = gfs2_flock, +const struct file_operations gfs2_dir_fops = { + .readdir = gfs2_readdir, + .unlocked_ioctl = gfs2_ioctl, + .open = gfs2_open, + .release = gfs2_close, + .fsync = gfs2_fsync, + .lock = gfs2_lock, + .flock = gfs2_flock, };