Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: remove detritus left by "mm: make read_cache_page synchronous" fix fs/sysv s_dirt handling fat: convert to use the new truncate convention. ext2: convert to use the new truncate convention. tmpfs: convert to use the new truncate convention fs: convert simple fs to new truncate kill spurious reference to vmtruncate fs: introduce new truncate sequence fs/super: fix kernel-doc warning fs/minix: bugfix, number of indirect block ptrs per block depends on block size rename the generic fsync implementations drop unused dentry argument to ->fsync fs: Add missing mutex_unlock Fix racy use of anon_inode_getfd() in perf_event.c get rid of the magic around f_count in aio VFS: fix recent breakage of FS_REVAL_DOT Revert "anon_inode: set S_IFREG on the anon_inode"
This commit is contained in:
commit
89ad6a6173
@ -380,7 +380,7 @@ prototypes:
|
||||
int (*open) (struct inode *, struct file *);
|
||||
int (*flush) (struct file *);
|
||||
int (*release) (struct inode *, struct file *);
|
||||
int (*fsync) (struct file *, struct dentry *, int datasync);
|
||||
int (*fsync) (struct file *, int datasync);
|
||||
int (*aio_fsync) (struct kiocb *, int datasync);
|
||||
int (*fasync) (int, struct file *, int);
|
||||
int (*lock) (struct file *, int, struct file_lock *);
|
||||
|
@ -401,11 +401,16 @@ otherwise noted.
|
||||
started might not be in the page cache at the end of the
|
||||
walk).
|
||||
|
||||
truncate: called by the VFS to change the size of a file. The
|
||||
truncate: Deprecated. This will not be called if ->setsize is defined.
|
||||
Called by the VFS to change the size of a file. The
|
||||
i_size field of the inode is set to the desired size by the
|
||||
VFS before this method is called. This method is called by
|
||||
the truncate(2) system call and related functionality.
|
||||
|
||||
Note: ->truncate and vmtruncate are deprecated. Do not add new
|
||||
instances/calls of these. Filesystems should be converted to do their
|
||||
truncate sequence via ->setattr().
|
||||
|
||||
permission: called by the VFS to check for access rights on a POSIX-like
|
||||
filesystem.
|
||||
|
||||
@ -729,7 +734,7 @@ struct file_operations {
|
||||
int (*open) (struct inode *, struct file *);
|
||||
int (*flush) (struct file *);
|
||||
int (*release) (struct inode *, struct file *);
|
||||
int (*fsync) (struct file *, struct dentry *, int datasync);
|
||||
int (*fsync) (struct file *, int datasync);
|
||||
int (*aio_fsync) (struct kiocb *, int datasync);
|
||||
int (*fasync) (int, struct file *, int);
|
||||
int (*lock) (struct file *, int, struct file_lock *);
|
||||
|
@ -1849,8 +1849,7 @@ static int spufs_mfc_flush(struct file *file, fl_owner_t id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,
|
||||
int datasync)
|
||||
static int spufs_mfc_fsync(struct file *file, int datasync)
|
||||
{
|
||||
return spufs_mfc_flush(file, NULL);
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ const struct file_operations spufs_context_fops = {
|
||||
.llseek = dcache_dir_lseek,
|
||||
.read = generic_read_dir,
|
||||
.readdir = dcache_readdir,
|
||||
.fsync = simple_sync_file,
|
||||
.fsync = noop_fsync,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(spufs_context_fops);
|
||||
|
||||
|
@ -305,8 +305,7 @@ static int ps3flash_flush(struct file *file, fl_owner_t id)
|
||||
return ps3flash_writeback(ps3flash_dev);
|
||||
}
|
||||
|
||||
static int ps3flash_fsync(struct file *file, struct dentry *dentry,
|
||||
int datasync)
|
||||
static int ps3flash_fsync(struct file *file, int datasync)
|
||||
{
|
||||
return ps3flash_writeback(ps3flash_dev);
|
||||
}
|
||||
|
@ -189,8 +189,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
static int vol_cdev_fsync(struct file *file, struct dentry *dentry,
|
||||
int datasync)
|
||||
static int vol_cdev_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct ubi_volume_desc *desc = file->private_data;
|
||||
struct ubi_device *ubi = desc->vol->ubi;
|
||||
|
@ -880,7 +880,7 @@ static struct inode *pohmelfs_alloc_inode(struct super_block *sb)
|
||||
/*
|
||||
* We want fsync() to work on POHMELFS.
|
||||
*/
|
||||
static int pohmelfs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
static int pohmelfs_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct writeback_control wbc = {
|
||||
|
@ -794,7 +794,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
}
|
||||
|
||||
static int
|
||||
printer_fsync(struct file *fd, struct dentry *dentry, int datasync)
|
||||
printer_fsync(struct file *fd, int datasync)
|
||||
{
|
||||
struct printer_dev *dev = fd->private_data;
|
||||
unsigned long flags;
|
||||
|
@ -66,7 +66,7 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
int fb_deferred_io_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct fb_info *info = file->private_data;
|
||||
|
||||
|
@ -257,15 +257,13 @@ v9fs_file_write(struct file *filp, const char __user * data,
|
||||
return total;
|
||||
}
|
||||
|
||||
static int v9fs_file_fsync(struct file *filp, struct dentry *dentry,
|
||||
int datasync)
|
||||
static int v9fs_file_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
struct p9_fid *fid;
|
||||
struct p9_wstat wstat;
|
||||
int retval;
|
||||
|
||||
P9_DPRINTK(P9_DEBUG_VFS, "filp %p dentry %p datasync %x\n", filp,
|
||||
dentry, datasync);
|
||||
P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
|
||||
|
||||
fid = filp->private_data;
|
||||
v9fs_blank_wstat(&wstat);
|
||||
|
@ -197,7 +197,7 @@ const struct file_operations adfs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.llseek = generic_file_llseek,
|
||||
.readdir = adfs_readdir,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -26,7 +26,7 @@ const struct file_operations adfs_file_operations = {
|
||||
.read = do_sync_read,
|
||||
.aio_read = generic_file_aio_read,
|
||||
.mmap = generic_file_mmap,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
.write = do_sync_write,
|
||||
.aio_write = generic_file_aio_write,
|
||||
.splice_read = generic_file_splice_read,
|
||||
|
@ -322,8 +322,9 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/* XXX: this is missing some actual on-disk truncation.. */
|
||||
if (ia_valid & ATTR_SIZE)
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
error = simple_setsize(inode, attr->ia_size);
|
||||
|
||||
if (error)
|
||||
goto out;
|
||||
|
@ -183,7 +183,7 @@ extern int affs_add_entry(struct inode *dir, struct inode *inode, struct dent
|
||||
|
||||
void affs_free_prealloc(struct inode *inode);
|
||||
extern void affs_truncate(struct inode *);
|
||||
int affs_file_fsync(struct file *, struct dentry *, int);
|
||||
int affs_file_fsync(struct file *, int);
|
||||
|
||||
/* dir.c */
|
||||
|
||||
|
@ -916,9 +916,9 @@ affs_truncate(struct inode *inode)
|
||||
affs_free_prealloc(inode);
|
||||
}
|
||||
|
||||
int affs_file_fsync(struct file *filp, struct dentry *dentry, int datasync)
|
||||
int affs_file_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
struct inode * inode = dentry->d_inode;
|
||||
struct inode *inode = filp->f_mapping->host;
|
||||
int ret, err;
|
||||
|
||||
ret = write_inode_now(inode, 0);
|
||||
|
@ -740,7 +740,7 @@ extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
|
||||
extern ssize_t afs_file_write(struct kiocb *, const struct iovec *,
|
||||
unsigned long, loff_t);
|
||||
extern int afs_writeback_all(struct afs_vnode *);
|
||||
extern int afs_fsync(struct file *, struct dentry *, int);
|
||||
extern int afs_fsync(struct file *, int);
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -701,8 +701,9 @@ int afs_writeback_all(struct afs_vnode *vnode)
|
||||
* - the return status from this call provides a reliable indication of
|
||||
* whether any write errors occurred for this process.
|
||||
*/
|
||||
int afs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
int afs_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct afs_writeback *wb, *xwb;
|
||||
struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
|
||||
int ret;
|
||||
|
6
fs/aio.c
6
fs/aio.c
@ -527,7 +527,7 @@ static void aio_fput_routine(struct work_struct *data)
|
||||
|
||||
/* Complete the fput(s) */
|
||||
if (req->ki_filp != NULL)
|
||||
__fput(req->ki_filp);
|
||||
fput(req->ki_filp);
|
||||
|
||||
/* Link the iocb into the context's free list */
|
||||
spin_lock_irq(&ctx->ctx_lock);
|
||||
@ -560,11 +560,11 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
|
||||
|
||||
/*
|
||||
* Try to optimize the aio and eventfd file* puts, by avoiding to
|
||||
* schedule work in case it is not __fput() time. In normal cases,
|
||||
* schedule work in case it is not final fput() time. In normal cases,
|
||||
* we would not be holding the last reference to the file*, so
|
||||
* this function will be executed w/out any aio kthread wakeup.
|
||||
*/
|
||||
if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) {
|
||||
if (unlikely(!fput_atomic(req->ki_filp))) {
|
||||
get_ioctx(ctx);
|
||||
spin_lock(&fput_lock);
|
||||
list_add(&req->ki_list, &fput_head);
|
||||
|
@ -205,7 +205,7 @@ static struct inode *anon_inode_mkinode(void)
|
||||
* that it already _is_ on the dirty list.
|
||||
*/
|
||||
inode->i_state = I_DIRTY;
|
||||
inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
|
||||
inode->i_mode = S_IRUSR | S_IWUSR;
|
||||
inode->i_uid = current_fsuid();
|
||||
inode->i_gid = current_fsgid();
|
||||
inode->i_flags |= S_PRIVATE;
|
||||
|
50
fs/attr.c
50
fs/attr.c
@ -67,14 +67,14 @@ EXPORT_SYMBOL(inode_change_ok);
|
||||
* @offset: the new size to assign to the inode
|
||||
* @Returns: 0 on success, -ve errno on failure
|
||||
*
|
||||
* inode_newsize_ok must be called with i_mutex held.
|
||||
*
|
||||
* inode_newsize_ok will check filesystem limits and ulimits to check that the
|
||||
* new inode size is within limits. inode_newsize_ok will also send SIGXFSZ
|
||||
* when necessary. Caller must not proceed with inode size change if failure is
|
||||
* returned. @inode must be a file (not directory), with appropriate
|
||||
* permissions to allow truncate (inode_newsize_ok does NOT check these
|
||||
* conditions).
|
||||
*
|
||||
* inode_newsize_ok must be called with i_mutex held.
|
||||
*/
|
||||
int inode_newsize_ok(const struct inode *inode, loff_t offset)
|
||||
{
|
||||
@ -104,17 +104,25 @@ int inode_newsize_ok(const struct inode *inode, loff_t offset)
|
||||
}
|
||||
EXPORT_SYMBOL(inode_newsize_ok);
|
||||
|
||||
int inode_setattr(struct inode * inode, struct iattr * attr)
|
||||
/**
|
||||
* generic_setattr - copy simple metadata updates into the generic inode
|
||||
* @inode: the inode to be updated
|
||||
* @attr: the new attributes
|
||||
*
|
||||
* generic_setattr must be called with i_mutex held.
|
||||
*
|
||||
* generic_setattr updates the inode's metadata with that specified
|
||||
* in attr. Noticably missing is inode size update, which is more complex
|
||||
* as it requires pagecache updates. See simple_setsize.
|
||||
*
|
||||
* The inode is not marked as dirty after this operation. The rationale is
|
||||
* that for "simple" filesystems, the struct inode is the inode storage.
|
||||
* The caller is free to mark the inode dirty afterwards if needed.
|
||||
*/
|
||||
void generic_setattr(struct inode *inode, const struct iattr *attr)
|
||||
{
|
||||
unsigned int ia_valid = attr->ia_valid;
|
||||
|
||||
if (ia_valid & ATTR_SIZE &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
int error = vmtruncate(inode, attr->ia_size);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (ia_valid & ATTR_UID)
|
||||
inode->i_uid = attr->ia_uid;
|
||||
if (ia_valid & ATTR_GID)
|
||||
@ -135,6 +143,28 @@ int inode_setattr(struct inode * inode, struct iattr * attr)
|
||||
mode &= ~S_ISGID;
|
||||
inode->i_mode = mode;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(generic_setattr);
|
||||
|
||||
/*
|
||||
* note this function is deprecated, the new truncate sequence should be
|
||||
* used instead -- see eg. simple_setsize, generic_setattr.
|
||||
*/
|
||||
int inode_setattr(struct inode *inode, const struct iattr *attr)
|
||||
{
|
||||
unsigned int ia_valid = attr->ia_valid;
|
||||
|
||||
if (ia_valid & ATTR_SIZE &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
int error;
|
||||
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
generic_setattr(inode, attr);
|
||||
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
return 0;
|
||||
|
@ -93,8 +93,7 @@ static int bad_file_release(struct inode *inode, struct file *filp)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_file_fsync(struct file *file, struct dentry *dentry,
|
||||
int datasync)
|
||||
static int bad_file_fsync(struct file *file, int datasync)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ static int bfs_readdir(struct file *f, void *dirent, filldir_t filldir)
|
||||
const struct file_operations bfs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = bfs_readdir,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
|
@ -172,8 +172,9 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
|
||||
return blockdev_direct_IO_no_locking(rw, iocb, inode, I_BDEV(inode),
|
||||
iov, offset, nr_segs, blkdev_get_blocks, NULL);
|
||||
return blockdev_direct_IO_no_locking_newtrunc(rw, iocb, inode,
|
||||
I_BDEV(inode), iov, offset, nr_segs,
|
||||
blkdev_get_blocks, NULL);
|
||||
}
|
||||
|
||||
int __sync_blockdev(struct block_device *bdev, int wait)
|
||||
@ -309,8 +310,8 @@ static int blkdev_write_begin(struct file *file, struct address_space *mapping,
|
||||
struct page **pagep, void **fsdata)
|
||||
{
|
||||
*pagep = NULL;
|
||||
return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
|
||||
blkdev_get_block);
|
||||
return block_write_begin_newtrunc(file, mapping, pos, len, flags,
|
||||
pagep, fsdata, blkdev_get_block);
|
||||
}
|
||||
|
||||
static int blkdev_write_end(struct file *file, struct address_space *mapping,
|
||||
@ -358,12 +359,7 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Filp is never NULL; the only case when ->fsync() is called with
|
||||
* NULL first argument is nfsd_sync_dir() and that's not a directory.
|
||||
*/
|
||||
|
||||
int blkdev_fsync(struct file *filp, struct dentry *dentry, int datasync)
|
||||
int blkdev_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
struct inode *bd_inode = filp->f_mapping->host;
|
||||
struct block_device *bdev = I_BDEV(bd_inode);
|
||||
|
@ -2434,7 +2434,7 @@ void btrfs_update_iflags(struct inode *inode);
|
||||
void btrfs_inherit_iflags(struct inode *inode, struct inode *dir);
|
||||
|
||||
/* file.c */
|
||||
int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync);
|
||||
int btrfs_sync_file(struct file *file, int datasync);
|
||||
int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||
int skip_pinned);
|
||||
int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
|
||||
|
@ -1101,8 +1101,9 @@ int btrfs_release_file(struct inode *inode, struct file *filp)
|
||||
* important optimization for directories because holding the mutex prevents
|
||||
* new operations on the dir while we write to disk.
|
||||
*/
|
||||
int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
|
||||
int btrfs_sync_file(struct file *file, int datasync)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
int ret = 0;
|
||||
|
123
fs/buffer.c
123
fs/buffer.c
@ -1949,14 +1949,11 @@ static int __block_commit_write(struct inode *inode, struct page *page,
|
||||
}
|
||||
|
||||
/*
|
||||
* block_write_begin takes care of the basic task of block allocation and
|
||||
* bringing partial write blocks uptodate first.
|
||||
*
|
||||
* If *pagep is not NULL, then block_write_begin uses the locked page
|
||||
* at *pagep rather than allocating its own. In this case, the page will
|
||||
* not be unlocked or deallocated on failure.
|
||||
* Filesystems implementing the new truncate sequence should use the
|
||||
* _newtrunc postfix variant which won't incorrectly call vmtruncate.
|
||||
* The filesystem needs to handle block truncation upon failure.
|
||||
*/
|
||||
int block_write_begin(struct file *file, struct address_space *mapping,
|
||||
int block_write_begin_newtrunc(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata,
|
||||
get_block_t *get_block)
|
||||
@ -1992,20 +1989,50 @@ int block_write_begin(struct file *file, struct address_space *mapping,
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
*pagep = NULL;
|
||||
|
||||
/*
|
||||
* prepare_write() may have instantiated a few blocks
|
||||
* outside i_size. Trim these off again. Don't need
|
||||
* i_size_read because we hold i_mutex.
|
||||
*/
|
||||
if (pos + len > inode->i_size)
|
||||
vmtruncate(inode, inode->i_size);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(block_write_begin_newtrunc);
|
||||
|
||||
/*
|
||||
* block_write_begin takes care of the basic task of block allocation and
|
||||
* bringing partial write blocks uptodate first.
|
||||
*
|
||||
* If *pagep is not NULL, then block_write_begin uses the locked page
|
||||
* at *pagep rather than allocating its own. In this case, the page will
|
||||
* not be unlocked or deallocated on failure.
|
||||
*/
|
||||
int block_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata,
|
||||
get_block_t *get_block)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = block_write_begin_newtrunc(file, mapping, pos, len, flags,
|
||||
pagep, fsdata, get_block);
|
||||
|
||||
/*
|
||||
* prepare_write() may have instantiated a few blocks
|
||||
* outside i_size. Trim these off again. Don't need
|
||||
* i_size_read because we hold i_mutex.
|
||||
*
|
||||
* Filesystems which pass down their own page also cannot
|
||||
* call into vmtruncate here because it would lead to lock
|
||||
* inversion problems (*pagep is locked). This is a further
|
||||
* example of where the old truncate sequence is inadequate.
|
||||
*/
|
||||
if (unlikely(ret) && *pagep == NULL) {
|
||||
loff_t isize = mapping->host->i_size;
|
||||
if (pos + len > isize)
|
||||
vmtruncate(mapping->host, isize);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(block_write_begin);
|
||||
|
||||
int block_write_end(struct file *file, struct address_space *mapping,
|
||||
@ -2324,7 +2351,7 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping,
|
||||
* For moronic filesystems that do not allow holes in file.
|
||||
* We may have to extend the file.
|
||||
*/
|
||||
int cont_write_begin(struct file *file, struct address_space *mapping,
|
||||
int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata,
|
||||
get_block_t *get_block, loff_t *bytes)
|
||||
@ -2345,11 +2372,30 @@ int cont_write_begin(struct file *file, struct address_space *mapping,
|
||||
}
|
||||
|
||||
*pagep = NULL;
|
||||
err = block_write_begin(file, mapping, pos, len,
|
||||
err = block_write_begin_newtrunc(file, mapping, pos, len,
|
||||
flags, pagep, fsdata, get_block);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(cont_write_begin_newtrunc);
|
||||
|
||||
int cont_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata,
|
||||
get_block_t *get_block, loff_t *bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = cont_write_begin_newtrunc(file, mapping, pos, len, flags,
|
||||
pagep, fsdata, get_block, bytes);
|
||||
if (unlikely(ret)) {
|
||||
loff_t isize = mapping->host->i_size;
|
||||
if (pos + len > isize)
|
||||
vmtruncate(mapping->host, isize);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cont_write_begin);
|
||||
|
||||
int block_prepare_write(struct page *page, unsigned from, unsigned to,
|
||||
@ -2381,7 +2427,7 @@ EXPORT_SYMBOL(block_commit_write);
|
||||
*
|
||||
* We are not allowed to take the i_mutex here so we have to play games to
|
||||
* protect against truncate races as the page could now be beyond EOF. Because
|
||||
* vmtruncate() writes the inode size before removing pages, once we have the
|
||||
* truncate writes the inode size before removing pages, once we have the
|
||||
* page lock we can determine safely if the page is beyond EOF. If it is not
|
||||
* beyond EOF, then the page is guaranteed safe against truncation until we
|
||||
* unlock the page.
|
||||
@ -2464,10 +2510,11 @@ static void attach_nobh_buffers(struct page *page, struct buffer_head *head)
|
||||
}
|
||||
|
||||
/*
|
||||
* On entry, the page is fully not uptodate.
|
||||
* On exit the page is fully uptodate in the areas outside (from,to)
|
||||
* Filesystems implementing the new truncate sequence should use the
|
||||
* _newtrunc postfix variant which won't incorrectly call vmtruncate.
|
||||
* The filesystem needs to handle block truncation upon failure.
|
||||
*/
|
||||
int nobh_write_begin(struct file *file, struct address_space *mapping,
|
||||
int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata,
|
||||
get_block_t *get_block)
|
||||
@ -2500,8 +2547,8 @@ int nobh_write_begin(struct file *file, struct address_space *mapping,
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
*pagep = NULL;
|
||||
return block_write_begin(file, mapping, pos, len, flags, pagep,
|
||||
fsdata, get_block);
|
||||
return block_write_begin_newtrunc(file, mapping, pos, len,
|
||||
flags, pagep, fsdata, get_block);
|
||||
}
|
||||
|
||||
if (PageMappedToDisk(page))
|
||||
@ -2605,8 +2652,34 @@ int nobh_write_begin(struct file *file, struct address_space *mapping,
|
||||
page_cache_release(page);
|
||||
*pagep = NULL;
|
||||
|
||||
if (pos + len > inode->i_size)
|
||||
vmtruncate(inode, inode->i_size);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(nobh_write_begin_newtrunc);
|
||||
|
||||
/*
|
||||
* On entry, the page is fully not uptodate.
|
||||
* On exit the page is fully uptodate in the areas outside (from,to)
|
||||
*/
|
||||
int nobh_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata,
|
||||
get_block_t *get_block)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags,
|
||||
pagep, fsdata, get_block);
|
||||
|
||||
/*
|
||||
* prepare_write() may have instantiated a few blocks
|
||||
* outside i_size. Trim these off again. Don't need
|
||||
* i_size_read because we hold i_mutex.
|
||||
*/
|
||||
if (unlikely(ret)) {
|
||||
loff_t isize = mapping->host->i_size;
|
||||
if (pos + len > isize)
|
||||
vmtruncate(mapping->host, isize);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1776,9 +1776,9 @@ static void sync_write_wait(struct inode *inode)
|
||||
spin_unlock(&ci->i_unsafe_lock);
|
||||
}
|
||||
|
||||
int ceph_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
int ceph_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
unsigned flush_tid;
|
||||
int ret;
|
||||
|
@ -1107,10 +1107,9 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
|
||||
* an fsync() on a dir will wait for any uncommitted directory
|
||||
* operations to commit.
|
||||
*/
|
||||
static int ceph_dir_fsync(struct file *file, struct dentry *dentry,
|
||||
int datasync)
|
||||
static int ceph_dir_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct list_head *head = &ci->i_unsafe_dirops;
|
||||
struct ceph_mds_request *req;
|
||||
|
@ -811,7 +811,7 @@ extern void ceph_put_cap(struct ceph_cap *cap);
|
||||
|
||||
extern void ceph_queue_caps_release(struct inode *inode);
|
||||
extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc);
|
||||
extern int ceph_fsync(struct file *file, struct dentry *dentry, int datasync);
|
||||
extern int ceph_fsync(struct file *file, int datasync);
|
||||
extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
|
||||
struct ceph_mds_session *session);
|
||||
extern int ceph_get_cap_mds(struct inode *inode);
|
||||
|
@ -84,7 +84,7 @@ extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
|
||||
extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
|
||||
size_t write_size, loff_t *poffset);
|
||||
extern int cifs_lock(struct file *, int, struct file_lock *);
|
||||
extern int cifs_fsync(struct file *, struct dentry *, int);
|
||||
extern int cifs_fsync(struct file *, int);
|
||||
extern int cifs_flush(struct file *, fl_owner_t id);
|
||||
extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
|
||||
extern const struct file_operations cifs_dir_ops;
|
||||
|
@ -1676,7 +1676,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
int cifs_fsync(struct file *file, int datasync)
|
||||
{
|
||||
int xid;
|
||||
int rc = 0;
|
||||
@ -1688,7 +1688,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
xid = GetXid();
|
||||
|
||||
cFYI(1, "Sync file - name: %s datasync: 0x%x",
|
||||
dentry->d_name.name, datasync);
|
||||
file->f_path.dentry->d_name.name, datasync);
|
||||
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (rc == 0) {
|
||||
|
@ -11,8 +11,7 @@ extern int coda_fake_statfs;
|
||||
|
||||
void coda_destroy_inodecache(void);
|
||||
int coda_init_inodecache(void);
|
||||
int coda_fsync(struct file *coda_file, struct dentry *coda_dentry,
|
||||
int datasync);
|
||||
int coda_fsync(struct file *coda_file, int datasync);
|
||||
void coda_sysctl_init(void);
|
||||
void coda_sysctl_clean(void);
|
||||
|
||||
|
@ -202,10 +202,10 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
|
||||
int coda_fsync(struct file *coda_file, int datasync)
|
||||
{
|
||||
struct file *host_file;
|
||||
struct inode *coda_inode = coda_dentry->d_inode;
|
||||
struct inode *coda_inode = coda_file->f_path.dentry->d_inode;
|
||||
struct coda_file_info *cfi;
|
||||
int err = 0;
|
||||
|
||||
|
@ -72,16 +72,11 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
|
||||
if (!sd)
|
||||
return -EINVAL;
|
||||
|
||||
error = simple_setattr(dentry, iattr);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
sd_iattr = sd->s_iattr;
|
||||
|
||||
error = inode_change_ok(inode, iattr);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = inode_setattr(inode, iattr);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!sd_iattr) {
|
||||
/* setting attributes for the first time, allocate now */
|
||||
sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
|
||||
|
@ -1134,27 +1134,8 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a library function for use by filesystem drivers.
|
||||
*
|
||||
* The locking rules are governed by the flags parameter:
|
||||
* - if the flags value contains DIO_LOCKING we use a fancy locking
|
||||
* scheme for dumb filesystems.
|
||||
* For writes this function is called under i_mutex and returns with
|
||||
* i_mutex held, for reads, i_mutex is not held on entry, but it is
|
||||
* taken and dropped again before returning.
|
||||
* For reads and writes i_alloc_sem is taken in shared mode and released
|
||||
* on I/O completion (which may happen asynchronously after returning to
|
||||
* the caller).
|
||||
*
|
||||
* - if the flags value does NOT contain DIO_LOCKING we don't use any
|
||||
* internal locking but rather rely on the filesystem to synchronize
|
||||
* direct I/O reads/writes versus each other and truncate.
|
||||
* For reads and writes both i_mutex and i_alloc_sem are not held on
|
||||
* entry and are never taken.
|
||||
*/
|
||||
ssize_t
|
||||
__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
|
||||
__blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
|
||||
struct block_device *bdev, const struct iovec *iov, loff_t offset,
|
||||
unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
|
||||
dio_submit_t submit_io, int flags)
|
||||
@ -1247,9 +1228,46 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
|
||||
nr_segs, blkbits, get_block, end_io,
|
||||
submit_io, dio);
|
||||
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(__blockdev_direct_IO_newtrunc);
|
||||
|
||||
/*
|
||||
* This is a library function for use by filesystem drivers.
|
||||
*
|
||||
* The locking rules are governed by the flags parameter:
|
||||
* - if the flags value contains DIO_LOCKING we use a fancy locking
|
||||
* scheme for dumb filesystems.
|
||||
* For writes this function is called under i_mutex and returns with
|
||||
* i_mutex held, for reads, i_mutex is not held on entry, but it is
|
||||
* taken and dropped again before returning.
|
||||
* For reads and writes i_alloc_sem is taken in shared mode and released
|
||||
* on I/O completion (which may happen asynchronously after returning to
|
||||
* the caller).
|
||||
*
|
||||
* - if the flags value does NOT contain DIO_LOCKING we don't use any
|
||||
* internal locking but rather rely on the filesystem to synchronize
|
||||
* direct I/O reads/writes versus each other and truncate.
|
||||
* For reads and writes both i_mutex and i_alloc_sem are not held on
|
||||
* entry and are never taken.
|
||||
*/
|
||||
ssize_t
|
||||
__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
|
||||
struct block_device *bdev, const struct iovec *iov, loff_t offset,
|
||||
unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
|
||||
dio_submit_t submit_io, int flags)
|
||||
{
|
||||
ssize_t retval;
|
||||
|
||||
retval = __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov,
|
||||
offset, nr_segs, get_block, end_io, submit_io, flags);
|
||||
/*
|
||||
* In case of error extending write may have instantiated a few
|
||||
* blocks outside i_size. Trim these off again for DIO_LOCKING.
|
||||
* NOTE: DIO_NO_LOCK/DIO_OWN_LOCK callers have to handle this in
|
||||
* their own manner. This is a further example of where the old
|
||||
* truncate sequence is inadequate.
|
||||
*
|
||||
* NOTE: filesystems with their own locking have to handle this
|
||||
* on their own.
|
||||
@ -1257,12 +1275,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
|
||||
if (flags & DIO_LOCKING) {
|
||||
if (unlikely((rw & WRITE) && retval < 0)) {
|
||||
loff_t isize = i_size_read(inode);
|
||||
loff_t end = offset + iov_length(iov, nr_segs);
|
||||
|
||||
if (end > isize)
|
||||
vmtruncate(inode, isize);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(__blockdev_direct_IO);
|
||||
|
@ -274,7 +274,7 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
|
||||
}
|
||||
|
||||
static int
|
||||
ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
ecryptfs_fsync(struct file *file, int datasync)
|
||||
{
|
||||
return vfs_fsync(ecryptfs_file_to_lower(file), datasync);
|
||||
}
|
||||
|
@ -805,7 +805,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
|
||||
- (ia->ia_size & ~PAGE_CACHE_MASK));
|
||||
|
||||
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
|
||||
rc = vmtruncate(inode, ia->ia_size);
|
||||
rc = simple_setsize(inode, ia->ia_size);
|
||||
if (rc)
|
||||
goto out;
|
||||
lower_ia->ia_size = ia->ia_size;
|
||||
@ -830,7 +830,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
vmtruncate(inode, ia->ia_size);
|
||||
simple_setsize(inode, ia->ia_size);
|
||||
rc = ecryptfs_write_inode_size_to_metadata(inode);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "Problem with "
|
||||
|
@ -40,12 +40,11 @@ static int exofs_release_file(struct inode *inode, struct file *filp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
|
||||
int datasync)
|
||||
static int exofs_file_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
int ret;
|
||||
struct address_space *mapping = filp->f_mapping;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = mapping->host;
|
||||
struct super_block *sb;
|
||||
|
||||
ret = filemap_write_and_wait(mapping);
|
||||
@ -66,7 +65,7 @@ static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
|
||||
|
||||
static int exofs_flush(struct file *file, fl_owner_t id)
|
||||
{
|
||||
exofs_file_fsync(file, file->f_path.dentry, 1);
|
||||
exofs_file_fsync(file, 1);
|
||||
/* TODO: Flush the OSD target */
|
||||
return 0;
|
||||
}
|
||||
|
@ -122,7 +122,6 @@ extern int ext2_write_inode (struct inode *, struct writeback_control *);
|
||||
extern void ext2_delete_inode (struct inode *);
|
||||
extern int ext2_sync_inode (struct inode *);
|
||||
extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
|
||||
extern void ext2_truncate (struct inode *);
|
||||
extern int ext2_setattr (struct dentry *, struct iattr *);
|
||||
extern void ext2_set_inode_flags(struct inode *inode);
|
||||
extern void ext2_get_inode_flags(struct ext2_inode_info *);
|
||||
@ -155,7 +154,7 @@ extern void ext2_write_super (struct super_block *);
|
||||
extern const struct file_operations ext2_dir_operations;
|
||||
|
||||
/* file.c */
|
||||
extern int ext2_fsync(struct file *file, struct dentry *dentry, int datasync);
|
||||
extern int ext2_fsync(struct file *file, int datasync);
|
||||
extern const struct inode_operations ext2_file_inode_operations;
|
||||
extern const struct file_operations ext2_file_operations;
|
||||
extern const struct file_operations ext2_xip_file_operations;
|
||||
|
@ -40,13 +40,13 @@ static int ext2_release_file (struct inode * inode, struct file * filp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
int ext2_fsync(struct file *file, int datasync)
|
||||
{
|
||||
int ret;
|
||||
struct super_block *sb = dentry->d_inode->i_sb;
|
||||
struct super_block *sb = file->f_mapping->host->i_sb;
|
||||
struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
|
||||
|
||||
ret = simple_fsync(file, dentry, datasync);
|
||||
ret = generic_file_fsync(file, datasync);
|
||||
if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) {
|
||||
/* We don't really know where the IO error happened... */
|
||||
ext2_error(sb, __func__,
|
||||
@ -95,7 +95,6 @@ const struct file_operations ext2_xip_file_operations = {
|
||||
#endif
|
||||
|
||||
const struct inode_operations ext2_file_inode_operations = {
|
||||
.truncate = ext2_truncate,
|
||||
#ifdef CONFIG_EXT2_FS_XATTR
|
||||
.setxattr = generic_setxattr,
|
||||
.getxattr = generic_getxattr,
|
||||
|
151
fs/ext2/inode.c
151
fs/ext2/inode.c
@ -54,6 +54,18 @@ static inline int ext2_inode_is_fast_symlink(struct inode *inode)
|
||||
inode->i_blocks - ea_blocks == 0);
|
||||
}
|
||||
|
||||
static void ext2_truncate_blocks(struct inode *inode, loff_t offset);
|
||||
|
||||
static void ext2_write_failed(struct address_space *mapping, loff_t to)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
|
||||
if (to > inode->i_size) {
|
||||
truncate_pagecache(inode, to, inode->i_size);
|
||||
ext2_truncate_blocks(inode, inode->i_size);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called at the last iput() if i_nlink is zero.
|
||||
*/
|
||||
@ -71,7 +83,7 @@ void ext2_delete_inode (struct inode * inode)
|
||||
|
||||
inode->i_size = 0;
|
||||
if (inode->i_blocks)
|
||||
ext2_truncate (inode);
|
||||
ext2_truncate_blocks(inode, 0);
|
||||
ext2_free_inode (inode);
|
||||
|
||||
return;
|
||||
@ -757,8 +769,8 @@ int __ext2_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
{
|
||||
return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
|
||||
ext2_get_block);
|
||||
return block_write_begin_newtrunc(file, mapping, pos, len, flags,
|
||||
pagep, fsdata, ext2_get_block);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -766,8 +778,25 @@ ext2_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*pagep = NULL;
|
||||
return __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata);
|
||||
ret = __ext2_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
|
||||
if (ret < 0)
|
||||
ext2_write_failed(mapping, pos + len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ext2_write_end(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned copied,
|
||||
struct page *page, void *fsdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
|
||||
if (ret < len)
|
||||
ext2_write_failed(mapping, pos + len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -775,13 +804,18 @@ ext2_nobh_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Dir-in-pagecache still uses ext2_write_begin. Would have to rework
|
||||
* directory handling code to pass around offsets rather than struct
|
||||
* pages in order to make this work easily.
|
||||
*/
|
||||
return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
|
||||
ext2_get_block);
|
||||
ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags, pagep,
|
||||
fsdata, ext2_get_block);
|
||||
if (ret < 0)
|
||||
ext2_write_failed(mapping, pos + len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ext2_nobh_writepage(struct page *page,
|
||||
@ -800,10 +834,15 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||||
loff_t offset, unsigned long nr_segs)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
struct inode *inode = mapping->host;
|
||||
ssize_t ret;
|
||||
|
||||
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
|
||||
offset, nr_segs, ext2_get_block, NULL);
|
||||
ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
|
||||
iov, offset, nr_segs, ext2_get_block, NULL);
|
||||
if (ret < 0 && (rw & WRITE))
|
||||
ext2_write_failed(mapping, offset + iov_length(iov, nr_segs));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -818,7 +857,7 @@ const struct address_space_operations ext2_aops = {
|
||||
.writepage = ext2_writepage,
|
||||
.sync_page = block_sync_page,
|
||||
.write_begin = ext2_write_begin,
|
||||
.write_end = generic_write_end,
|
||||
.write_end = ext2_write_end,
|
||||
.bmap = ext2_bmap,
|
||||
.direct_IO = ext2_direct_IO,
|
||||
.writepages = ext2_writepages,
|
||||
@ -1027,7 +1066,7 @@ static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int de
|
||||
ext2_free_data(inode, p, q);
|
||||
}
|
||||
|
||||
void ext2_truncate(struct inode *inode)
|
||||
static void __ext2_truncate_blocks(struct inode *inode, loff_t offset)
|
||||
{
|
||||
__le32 *i_data = EXT2_I(inode)->i_data;
|
||||
struct ext2_inode_info *ei = EXT2_I(inode);
|
||||
@ -1039,27 +1078,8 @@ void ext2_truncate(struct inode *inode)
|
||||
int n;
|
||||
long iblock;
|
||||
unsigned blocksize;
|
||||
|
||||
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
||||
S_ISLNK(inode->i_mode)))
|
||||
return;
|
||||
if (ext2_inode_is_fast_symlink(inode))
|
||||
return;
|
||||
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
|
||||
return;
|
||||
|
||||
blocksize = inode->i_sb->s_blocksize;
|
||||
iblock = (inode->i_size + blocksize-1)
|
||||
>> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
|
||||
|
||||
if (mapping_is_xip(inode->i_mapping))
|
||||
xip_truncate_page(inode->i_mapping, inode->i_size);
|
||||
else if (test_opt(inode->i_sb, NOBH))
|
||||
nobh_truncate_page(inode->i_mapping,
|
||||
inode->i_size, ext2_get_block);
|
||||
else
|
||||
block_truncate_page(inode->i_mapping,
|
||||
inode->i_size, ext2_get_block);
|
||||
iblock = (offset + blocksize-1) >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
|
||||
|
||||
n = ext2_block_to_path(inode, iblock, offsets, NULL);
|
||||
if (n == 0)
|
||||
@ -1127,6 +1147,62 @@ void ext2_truncate(struct inode *inode)
|
||||
ext2_discard_reservation(inode);
|
||||
|
||||
mutex_unlock(&ei->truncate_mutex);
|
||||
}
|
||||
|
||||
static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
|
||||
{
|
||||
/*
|
||||
* XXX: it seems like a bug here that we don't allow
|
||||
* IS_APPEND inode to have blocks-past-i_size trimmed off.
|
||||
* review and fix this.
|
||||
*
|
||||
* Also would be nice to be able to handle IO errors and such,
|
||||
* but that's probably too much to ask.
|
||||
*/
|
||||
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
||||
S_ISLNK(inode->i_mode)))
|
||||
return;
|
||||
if (ext2_inode_is_fast_symlink(inode))
|
||||
return;
|
||||
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
|
||||
return;
|
||||
__ext2_truncate_blocks(inode, offset);
|
||||
}
|
||||
|
||||
int ext2_setsize(struct inode *inode, loff_t newsize)
|
||||
{
|
||||
loff_t oldsize;
|
||||
int error;
|
||||
|
||||
error = inode_newsize_ok(inode, newsize);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
||||
S_ISLNK(inode->i_mode)))
|
||||
return -EINVAL;
|
||||
if (ext2_inode_is_fast_symlink(inode))
|
||||
return -EINVAL;
|
||||
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
|
||||
return -EPERM;
|
||||
|
||||
if (mapping_is_xip(inode->i_mapping))
|
||||
error = xip_truncate_page(inode->i_mapping, newsize);
|
||||
else if (test_opt(inode->i_sb, NOBH))
|
||||
error = nobh_truncate_page(inode->i_mapping,
|
||||
newsize, ext2_get_block);
|
||||
else
|
||||
error = block_truncate_page(inode->i_mapping,
|
||||
newsize, ext2_get_block);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
oldsize = inode->i_size;
|
||||
i_size_write(inode, newsize);
|
||||
truncate_pagecache(inode, oldsize, newsize);
|
||||
|
||||
__ext2_truncate_blocks(inode, newsize);
|
||||
|
||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
|
||||
if (inode_needs_sync(inode)) {
|
||||
sync_mapping_buffers(inode->i_mapping);
|
||||
@ -1134,6 +1210,8 @@ void ext2_truncate(struct inode *inode)
|
||||
} else {
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino,
|
||||
@ -1474,8 +1552,15 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
error = inode_setattr(inode, iattr);
|
||||
if (!error && (iattr->ia_valid & ATTR_MODE))
|
||||
if (iattr->ia_valid & ATTR_SIZE) {
|
||||
error = ext2_setsize(inode, iattr->ia_size);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
generic_setattr(inode, iattr);
|
||||
if (iattr->ia_valid & ATTR_MODE)
|
||||
error = ext2_acl_chmod(inode);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -43,9 +43,9 @@
|
||||
* inode to disk.
|
||||
*/
|
||||
|
||||
int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync)
|
||||
int ext3_sync_file(struct file *file, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct ext3_inode_info *ei = EXT3_I(inode);
|
||||
journal_t *journal = EXT3_SB(inode->i_sb)->s_journal;
|
||||
int ret, needs_barrier = 0;
|
||||
|
@ -1519,7 +1519,7 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
|
||||
extern void ext4_htree_free_dir_info(struct dir_private_info *p);
|
||||
|
||||
/* fsync.c */
|
||||
extern int ext4_sync_file(struct file *, struct dentry *, int);
|
||||
extern int ext4_sync_file(struct file *, int);
|
||||
|
||||
/* hash.c */
|
||||
extern int ext4fs_dirhash(const char *name, int len, struct
|
||||
|
@ -71,9 +71,9 @@ static void ext4_sync_parent(struct inode *inode)
|
||||
* i_mutex lock is held when entering and exiting this function
|
||||
*/
|
||||
|
||||
int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
|
||||
int ext4_sync_file(struct file *file, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
|
||||
int ret;
|
||||
@ -81,7 +81,7 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
|
||||
|
||||
J_ASSERT(ext4_journal_current_handle() == NULL);
|
||||
|
||||
trace_ext4_sync_file(file, dentry, datasync);
|
||||
trace_ext4_sync_file(file, datasync);
|
||||
|
||||
if (inode->i_sb->s_flags & MS_RDONLY)
|
||||
return 0;
|
||||
@ -91,7 +91,7 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
|
||||
return ret;
|
||||
|
||||
if (!journal) {
|
||||
ret = simple_fsync(file, dentry, datasync);
|
||||
ret = generic_file_fsync(file, datasync);
|
||||
if (!ret && !list_empty(&inode->i_dentry))
|
||||
ext4_sync_parent(inode);
|
||||
return ret;
|
||||
|
@ -306,11 +306,11 @@ extern long fat_generic_ioctl(struct file *filp, unsigned int cmd,
|
||||
extern const struct file_operations fat_file_operations;
|
||||
extern const struct inode_operations fat_file_inode_operations;
|
||||
extern int fat_setattr(struct dentry * dentry, struct iattr * attr);
|
||||
extern void fat_truncate(struct inode *inode);
|
||||
extern int fat_setsize(struct inode *inode, loff_t offset);
|
||||
extern void fat_truncate_blocks(struct inode *inode, loff_t offset);
|
||||
extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
struct kstat *stat);
|
||||
extern int fat_file_fsync(struct file *file, struct dentry *dentry,
|
||||
int datasync);
|
||||
extern int fat_file_fsync(struct file *file, int datasync);
|
||||
|
||||
/* fat/inode.c */
|
||||
extern void fat_attach(struct inode *inode, loff_t i_pos);
|
||||
|
@ -149,12 +149,12 @@ static int fat_file_release(struct inode *inode, struct file *filp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fat_file_fsync(struct file *filp, struct dentry *dentry, int datasync)
|
||||
int fat_file_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = filp->f_mapping->host;
|
||||
int res, err;
|
||||
|
||||
res = simple_fsync(filp, dentry, datasync);
|
||||
res = generic_file_fsync(filp, datasync);
|
||||
err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping);
|
||||
|
||||
return res ? res : err;
|
||||
@ -283,7 +283,7 @@ static int fat_free(struct inode *inode, int skip)
|
||||
return fat_free_clusters(inode, free_start);
|
||||
}
|
||||
|
||||
void fat_truncate(struct inode *inode)
|
||||
void fat_truncate_blocks(struct inode *inode, loff_t offset)
|
||||
{
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
|
||||
const unsigned int cluster_size = sbi->cluster_size;
|
||||
@ -293,10 +293,10 @@ void fat_truncate(struct inode *inode)
|
||||
* This protects against truncating a file bigger than it was then
|
||||
* trying to write into the hole.
|
||||
*/
|
||||
if (MSDOS_I(inode)->mmu_private > inode->i_size)
|
||||
MSDOS_I(inode)->mmu_private = inode->i_size;
|
||||
if (MSDOS_I(inode)->mmu_private > offset)
|
||||
MSDOS_I(inode)->mmu_private = offset;
|
||||
|
||||
nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits;
|
||||
nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits;
|
||||
|
||||
fat_free(inode, nr_clusters);
|
||||
fat_flush_inodes(inode->i_sb, inode, NULL);
|
||||
@ -364,6 +364,18 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fat_setsize(struct inode *inode, loff_t offset)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = simple_setsize(inode, offset);
|
||||
if (error)
|
||||
return error;
|
||||
fat_truncate_blocks(inode, offset);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)
|
||||
/* valid file mode bits */
|
||||
#define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO)
|
||||
@ -378,7 +390,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
/*
|
||||
* Expand the file. Since inode_setattr() updates ->i_size
|
||||
* before calling the ->truncate(), but FAT needs to fill the
|
||||
* hole before it.
|
||||
* hole before it. XXX: this is no longer true with new truncate
|
||||
* sequence.
|
||||
*/
|
||||
if (attr->ia_valid & ATTR_SIZE) {
|
||||
if (attr->ia_size > inode->i_size) {
|
||||
@ -427,15 +440,20 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
attr->ia_valid &= ~ATTR_MODE;
|
||||
}
|
||||
|
||||
if (attr->ia_valid)
|
||||
error = inode_setattr(inode, attr);
|
||||
if (attr->ia_valid & ATTR_SIZE) {
|
||||
error = fat_setsize(inode, attr->ia_size);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
generic_setattr(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fat_setattr);
|
||||
|
||||
const struct inode_operations fat_file_inode_operations = {
|
||||
.truncate = fat_truncate,
|
||||
.setattr = fat_setattr,
|
||||
.getattr = fat_getattr,
|
||||
};
|
||||
|
@ -142,14 +142,29 @@ static int fat_readpages(struct file *file, struct address_space *mapping,
|
||||
return mpage_readpages(mapping, pages, nr_pages, fat_get_block);
|
||||
}
|
||||
|
||||
static void fat_write_failed(struct address_space *mapping, loff_t to)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
|
||||
if (to > inode->i_size) {
|
||||
truncate_pagecache(inode, to, inode->i_size);
|
||||
fat_truncate_blocks(inode, inode->i_size);
|
||||
}
|
||||
}
|
||||
|
||||
static int fat_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
{
|
||||
int err;
|
||||
|
||||
*pagep = NULL;
|
||||
return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
|
||||
fat_get_block,
|
||||
err = cont_write_begin_newtrunc(file, mapping, pos, len, flags,
|
||||
pagep, fsdata, fat_get_block,
|
||||
&MSDOS_I(mapping->host)->mmu_private);
|
||||
if (err < 0)
|
||||
fat_write_failed(mapping, pos + len);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fat_write_end(struct file *file, struct address_space *mapping,
|
||||
@ -159,6 +174,8 @@ static int fat_write_end(struct file *file, struct address_space *mapping,
|
||||
struct inode *inode = mapping->host;
|
||||
int err;
|
||||
err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
|
||||
if (err < len)
|
||||
fat_write_failed(mapping, pos + len);
|
||||
if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {
|
||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
|
||||
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
|
||||
@ -172,7 +189,9 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
|
||||
loff_t offset, unsigned long nr_segs)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
struct inode *inode = mapping->host;
|
||||
ssize_t ret;
|
||||
|
||||
if (rw == WRITE) {
|
||||
/*
|
||||
@ -193,8 +212,12 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
|
||||
* FAT need to use the DIO_LOCKING for avoiding the race
|
||||
* condition of fat_get_block() and ->truncate().
|
||||
*/
|
||||
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
|
||||
offset, nr_segs, fat_get_block, NULL);
|
||||
ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
|
||||
iov, offset, nr_segs, fat_get_block, NULL);
|
||||
if (ret < 0 && (rw & WRITE))
|
||||
fat_write_failed(mapping, offset + iov_length(iov, nr_segs));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
|
||||
@ -429,7 +452,7 @@ static void fat_delete_inode(struct inode *inode)
|
||||
{
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
inode->i_size = 0;
|
||||
fat_truncate(inode);
|
||||
fat_truncate_blocks(inode, 0);
|
||||
clear_inode(inode);
|
||||
}
|
||||
|
||||
|
@ -194,14 +194,6 @@ struct file *alloc_file(struct path *path, fmode_t mode,
|
||||
}
|
||||
EXPORT_SYMBOL(alloc_file);
|
||||
|
||||
void fput(struct file *file)
|
||||
{
|
||||
if (atomic_long_dec_and_test(&file->f_count))
|
||||
__fput(file);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(fput);
|
||||
|
||||
/**
|
||||
* drop_file_write_access - give up ability to write to a file
|
||||
* @file: the file to which we will stop writing
|
||||
@ -227,10 +219,9 @@ void drop_file_write_access(struct file *file)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drop_file_write_access);
|
||||
|
||||
/* __fput is called from task context when aio completion releases the last
|
||||
* last use of a struct file *. Do not use otherwise.
|
||||
/* the real guts of fput() - releasing the last reference to file
|
||||
*/
|
||||
void __fput(struct file *file)
|
||||
static void __fput(struct file *file)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct vfsmount *mnt = file->f_path.mnt;
|
||||
@ -268,6 +259,14 @@ void __fput(struct file *file)
|
||||
mntput(mnt);
|
||||
}
|
||||
|
||||
void fput(struct file *file)
|
||||
{
|
||||
if (atomic_long_dec_and_test(&file->f_count))
|
||||
__fput(file);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(fput);
|
||||
|
||||
struct file *fget(unsigned int fd)
|
||||
{
|
||||
struct file *file;
|
||||
|
@ -1156,10 +1156,9 @@ static int fuse_dir_release(struct inode *inode, struct file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
|
||||
static int fuse_dir_fsync(struct file *file, int datasync)
|
||||
{
|
||||
/* nfsd can call this with no file */
|
||||
return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
|
||||
return fuse_fsync_common(file, datasync, 1);
|
||||
}
|
||||
|
||||
static bool update_mtime(unsigned ivalid)
|
||||
|
@ -351,10 +351,9 @@ static void fuse_sync_writes(struct inode *inode)
|
||||
fuse_release_nowrite(inode);
|
||||
}
|
||||
|
||||
int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
|
||||
int isdir)
|
||||
int fuse_fsync_common(struct file *file, int datasync, int isdir)
|
||||
{
|
||||
struct inode *inode = de->d_inode;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
struct fuse_file *ff = file->private_data;
|
||||
struct fuse_req *req;
|
||||
@ -403,9 +402,9 @@ int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
|
||||
static int fuse_fsync(struct file *file, int datasync)
|
||||
{
|
||||
return fuse_fsync_common(file, de, datasync, 0);
|
||||
return fuse_fsync_common(file, datasync, 0);
|
||||
}
|
||||
|
||||
void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos,
|
||||
|
@ -568,8 +568,7 @@ void fuse_release_common(struct file *file, int opcode);
|
||||
/**
|
||||
* Send FSYNC or FSYNCDIR request
|
||||
*/
|
||||
int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
|
||||
int isdir);
|
||||
int fuse_fsync_common(struct file *file, int datasync, int isdir);
|
||||
|
||||
/**
|
||||
* Notify poll wakeup
|
||||
|
@ -700,8 +700,14 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
|
||||
return 0;
|
||||
|
||||
page_cache_release(page);
|
||||
|
||||
/*
|
||||
* XXX(hch): the call below should probably be replaced with
|
||||
* a call to the gfs2-specific truncate blocks helper to actually
|
||||
* release disk blocks..
|
||||
*/
|
||||
if (pos + len > ip->i_inode.i_size)
|
||||
vmtruncate(&ip->i_inode, ip->i_inode.i_size);
|
||||
simple_setsize(&ip->i_inode, ip->i_inode.i_size);
|
||||
out_endtrans:
|
||||
gfs2_trans_end(sdp);
|
||||
out_trans_fail:
|
||||
|
@ -554,9 +554,9 @@ static int gfs2_close(struct inode *inode, struct file *file)
|
||||
* Returns: errno
|
||||
*/
|
||||
|
||||
static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
static int gfs2_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
|
||||
int ret = 0;
|
||||
|
||||
|
@ -1071,6 +1071,9 @@ int gfs2_permission(struct inode *inode, int mask)
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: should be changed to have proper ordering by opencoding simple_setsize
|
||||
*/
|
||||
static int setattr_size(struct inode *inode, struct iattr *attr)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
@ -1081,7 +1084,7 @@ static int setattr_size(struct inode *inode, struct iattr *attr)
|
||||
error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
|
||||
if (error)
|
||||
return error;
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
error = simple_setsize(inode, attr->ia_size);
|
||||
gfs2_trans_end(sdp);
|
||||
if (error)
|
||||
return error;
|
||||
|
@ -411,9 +411,9 @@ int hostfs_file_open(struct inode *ino, struct file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
int hostfs_fsync(struct file *file, int datasync)
|
||||
{
|
||||
return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
|
||||
return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
|
||||
}
|
||||
|
||||
static const struct file_operations hostfs_file_fops = {
|
||||
|
@ -19,9 +19,9 @@ static int hpfs_file_release(struct inode *inode, struct file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hpfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
int hpfs_file_fsync(struct file *file, int datasync)
|
||||
{
|
||||
/*return file_fsync(file, dentry);*/
|
||||
/*return file_fsync(file, datasync);*/
|
||||
return 0; /* Don't fsync :-) */
|
||||
}
|
||||
|
||||
|
@ -268,7 +268,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, const char *,
|
||||
|
||||
/* file.c */
|
||||
|
||||
int hpfs_file_fsync(struct file *, struct dentry *, int);
|
||||
int hpfs_file_fsync(struct file *, int);
|
||||
extern const struct file_operations hpfs_file_ops;
|
||||
extern const struct inode_operations hpfs_file_iops;
|
||||
extern const struct address_space_operations hpfs_aops;
|
||||
|
@ -587,7 +587,7 @@ static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
static int hppfs_fsync(struct file *file, int datasync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -688,7 +688,7 @@ static void init_once(void *foo)
|
||||
const struct file_operations hugetlbfs_file_operations = {
|
||||
.read = hugetlbfs_read,
|
||||
.mmap = hugetlbfs_file_mmap,
|
||||
.fsync = simple_sync_file,
|
||||
.fsync = noop_fsync,
|
||||
.get_unmapped_area = hugetlb_get_unmapped_area,
|
||||
};
|
||||
|
||||
|
@ -26,9 +26,9 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
|
||||
struct page **pagep, void **fsdata);
|
||||
static int jffs2_readpage (struct file *filp, struct page *pg);
|
||||
|
||||
int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
|
||||
int jffs2_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = filp->f_mapping->host;
|
||||
struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
|
||||
|
||||
/* Trigger GC to flush any pending writes for this inode */
|
||||
|
@ -169,13 +169,13 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
/* We have to do the vmtruncate() without f->sem held, since
|
||||
/* We have to do the simple_setsize() without f->sem held, since
|
||||
some pages may be locked and waiting for it in readpage().
|
||||
We are protected from a simultaneous write() extending i_size
|
||||
back past iattr->ia_size, because do_truncate() holds the
|
||||
generic inode semaphore. */
|
||||
if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
|
||||
vmtruncate(inode, iattr->ia_size);
|
||||
simple_setsize(inode, iattr->ia_size);
|
||||
inode->i_blocks = (inode->i_size + 511) >> 9;
|
||||
}
|
||||
|
||||
|
@ -158,7 +158,7 @@ extern const struct inode_operations jffs2_dir_inode_operations;
|
||||
extern const struct file_operations jffs2_file_operations;
|
||||
extern const struct inode_operations jffs2_file_inode_operations;
|
||||
extern const struct address_space_operations jffs2_file_address_operations;
|
||||
int jffs2_fsync(struct file *, struct dentry *, int);
|
||||
int jffs2_fsync(struct file *, int);
|
||||
int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
|
||||
|
||||
/* ioctl.c */
|
||||
|
@ -27,9 +27,9 @@
|
||||
#include "jfs_acl.h"
|
||||
#include "jfs_debug.h"
|
||||
|
||||
int jfs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
int jfs_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
int rc = 0;
|
||||
|
||||
if (!(inode->i_state & I_DIRTY) ||
|
||||
|
@ -21,7 +21,7 @@
|
||||
struct fid;
|
||||
|
||||
extern struct inode *ialloc(struct inode *, umode_t);
|
||||
extern int jfs_fsync(struct file *, struct dentry *, int);
|
||||
extern int jfs_fsync(struct file *, int);
|
||||
extern long jfs_ioctl(struct file *, unsigned int, unsigned long);
|
||||
extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long);
|
||||
extern struct inode *jfs_iget(struct super_block *, unsigned long);
|
||||
|
108
fs/libfs.c
108
fs/libfs.c
@ -8,6 +8,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/writeback.h>
|
||||
@ -58,11 +59,6 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct na
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int simple_sync_file(struct file * file, struct dentry *dentry, int datasync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dcache_dir_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
static struct qstr cursor_name = {.len = 1, .name = "."};
|
||||
@ -190,7 +186,7 @@ const struct file_operations simple_dir_operations = {
|
||||
.llseek = dcache_dir_lseek,
|
||||
.read = generic_read_dir,
|
||||
.readdir = dcache_readdir,
|
||||
.fsync = simple_sync_file,
|
||||
.fsync = noop_fsync,
|
||||
};
|
||||
|
||||
const struct inode_operations simple_dir_inode_operations = {
|
||||
@ -330,6 +326,81 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* simple_setsize - handle core mm and vfs requirements for file size change
|
||||
* @inode: inode
|
||||
* @newsize: new file size
|
||||
*
|
||||
* Returns 0 on success, -error on failure.
|
||||
*
|
||||
* simple_setsize must be called with inode_mutex held.
|
||||
*
|
||||
* simple_setsize will check that the requested new size is OK (see
|
||||
* inode_newsize_ok), and then will perform the necessary i_size update
|
||||
* and pagecache truncation (if necessary). It will be typically be called
|
||||
* from the filesystem's setattr function when ATTR_SIZE is passed in.
|
||||
*
|
||||
* The inode itself must have correct permissions and attributes to allow
|
||||
* i_size to be changed, this function then just checks that the new size
|
||||
* requested is valid.
|
||||
*
|
||||
* In the case of simple in-memory filesystems with inodes stored solely
|
||||
* in the inode cache, and file data in the pagecache, nothing more needs
|
||||
* to be done to satisfy a truncate request. Filesystems with on-disk
|
||||
* blocks for example will need to free them in the case of truncate, in
|
||||
* that case it may be easier not to use simple_setsize (but each of its
|
||||
* components will likely be required at some point to update pagecache
|
||||
* and inode etc).
|
||||
*/
|
||||
int simple_setsize(struct inode *inode, loff_t newsize)
|
||||
{
|
||||
loff_t oldsize;
|
||||
int error;
|
||||
|
||||
error = inode_newsize_ok(inode, newsize);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
oldsize = inode->i_size;
|
||||
i_size_write(inode, newsize);
|
||||
truncate_pagecache(inode, oldsize, newsize);
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(simple_setsize);
|
||||
|
||||
/**
|
||||
* simple_setattr - setattr for simple in-memory filesystem
|
||||
* @dentry: dentry
|
||||
* @iattr: iattr structure
|
||||
*
|
||||
* Returns 0 on success, -error on failure.
|
||||
*
|
||||
* simple_setattr implements setattr for an in-memory filesystem which
|
||||
* does not store its own file data or metadata (eg. uses the page cache
|
||||
* and inode cache as its data store).
|
||||
*/
|
||||
int simple_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
|
||||
error = inode_change_ok(inode, iattr);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (iattr->ia_valid & ATTR_SIZE) {
|
||||
error = simple_setsize(inode, iattr->ia_size);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
generic_setattr(inode, iattr);
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(simple_setattr);
|
||||
|
||||
int simple_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
clear_highpage(page);
|
||||
@ -851,13 +922,22 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(generic_fh_to_parent);
|
||||
|
||||
int simple_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
/**
|
||||
* generic_file_fsync - generic fsync implementation for simple filesystems
|
||||
* @file: file to synchronize
|
||||
* @datasync: only synchronize essential metadata if true
|
||||
*
|
||||
* This is a generic implementation of the fsync method for simple
|
||||
* filesystems which track all non-inode metadata in the buffers list
|
||||
* hanging off the address_space structure.
|
||||
*/
|
||||
int generic_file_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct writeback_control wbc = {
|
||||
.sync_mode = WB_SYNC_ALL,
|
||||
.nr_to_write = 0, /* metadata-only; caller takes care of data */
|
||||
};
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
int err;
|
||||
int ret;
|
||||
|
||||
@ -872,7 +952,15 @@ int simple_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
ret = err;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(simple_fsync);
|
||||
EXPORT_SYMBOL(generic_file_fsync);
|
||||
|
||||
/*
|
||||
* No-op implementation of ->fsync for in-memory filesystems.
|
||||
*/
|
||||
int noop_fsync(struct file *file, int datasync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dcache_dir_close);
|
||||
EXPORT_SYMBOL(dcache_dir_lseek);
|
||||
@ -895,7 +983,7 @@ EXPORT_SYMBOL(simple_release_fs);
|
||||
EXPORT_SYMBOL(simple_rename);
|
||||
EXPORT_SYMBOL(simple_rmdir);
|
||||
EXPORT_SYMBOL(simple_statfs);
|
||||
EXPORT_SYMBOL(simple_sync_file);
|
||||
EXPORT_SYMBOL(noop_fsync);
|
||||
EXPORT_SYMBOL(simple_unlink);
|
||||
EXPORT_SYMBOL(simple_read_from_buffer);
|
||||
EXPORT_SYMBOL(simple_write_to_buffer);
|
||||
|
@ -219,9 +219,9 @@ int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
||||
}
|
||||
}
|
||||
|
||||
int logfs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
int logfs_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct super_block *sb = dentry->d_inode->i_sb;
|
||||
struct super_block *sb = file->f_mapping->host->i_sb;
|
||||
|
||||
logfs_write_anchor(sb);
|
||||
return 0;
|
||||
|
@ -506,7 +506,7 @@ extern const struct address_space_operations logfs_reg_aops;
|
||||
int logfs_readpage(struct file *file, struct page *page);
|
||||
int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
int logfs_fsync(struct file *file, struct dentry *dentry, int datasync);
|
||||
int logfs_fsync(struct file *file, int datasync);
|
||||
|
||||
/* gc.c */
|
||||
u32 get_best_cand(struct super_block *sb, struct candidate_list *list, u32 *ec);
|
||||
|
@ -22,7 +22,7 @@ const struct file_operations minix_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.readdir = minix_readdir,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
};
|
||||
|
||||
static inline void dir_put_page(struct page *page)
|
||||
@ -72,11 +72,8 @@ static struct page * dir_get_page(struct inode *dir, unsigned long n)
|
||||
{
|
||||
struct address_space *mapping = dir->i_mapping;
|
||||
struct page *page = read_mapping_page(mapping, n, NULL);
|
||||
if (!IS_ERR(page)) {
|
||||
if (!IS_ERR(page))
|
||||
kmap(page);
|
||||
if (!PageUptodate(page))
|
||||
goto fail;
|
||||
}
|
||||
return page;
|
||||
|
||||
fail:
|
||||
|
@ -19,7 +19,7 @@ const struct file_operations minix_file_operations = {
|
||||
.write = do_sync_write,
|
||||
.aio_write = generic_file_aio_write,
|
||||
.mmap = generic_file_mmap,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
.splice_read = generic_file_splice_read,
|
||||
};
|
||||
|
||||
|
@ -20,6 +20,9 @@ static inline block_t *i_data(struct inode *inode)
|
||||
return (block_t *)minix_i(inode)->u.i2_data;
|
||||
}
|
||||
|
||||
#define DIRCOUNT 7
|
||||
#define INDIRCOUNT(sb) (1 << ((sb)->s_blocksize_bits - 2))
|
||||
|
||||
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
|
||||
{
|
||||
int n = 0;
|
||||
@ -34,21 +37,21 @@ static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
|
||||
printk("MINIX-fs: block_to_path: "
|
||||
"block %ld too big on dev %s\n",
|
||||
block, bdevname(sb->s_bdev, b));
|
||||
} else if (block < 7) {
|
||||
} else if (block < DIRCOUNT) {
|
||||
offsets[n++] = block;
|
||||
} else if ((block -= 7) < 256) {
|
||||
offsets[n++] = 7;
|
||||
} else if ((block -= DIRCOUNT) < INDIRCOUNT(sb)) {
|
||||
offsets[n++] = DIRCOUNT;
|
||||
offsets[n++] = block;
|
||||
} else if ((block -= 256) < 256*256) {
|
||||
offsets[n++] = 8;
|
||||
offsets[n++] = block>>8;
|
||||
offsets[n++] = block & 255;
|
||||
} else if ((block -= INDIRCOUNT(sb)) < INDIRCOUNT(sb) * INDIRCOUNT(sb)) {
|
||||
offsets[n++] = DIRCOUNT + 1;
|
||||
offsets[n++] = block / INDIRCOUNT(sb);
|
||||
offsets[n++] = block % INDIRCOUNT(sb);
|
||||
} else {
|
||||
block -= 256*256;
|
||||
offsets[n++] = 9;
|
||||
offsets[n++] = block>>16;
|
||||
offsets[n++] = (block>>8) & 255;
|
||||
offsets[n++] = block & 255;
|
||||
block -= INDIRCOUNT(sb) * INDIRCOUNT(sb);
|
||||
offsets[n++] = DIRCOUNT + 2;
|
||||
offsets[n++] = (block / INDIRCOUNT(sb)) / INDIRCOUNT(sb);
|
||||
offsets[n++] = (block / INDIRCOUNT(sb)) % INDIRCOUNT(sb);
|
||||
offsets[n++] = block % INDIRCOUNT(sb);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
@ -1621,6 +1621,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
||||
case LAST_DOTDOT:
|
||||
follow_dotdot(nd);
|
||||
dir = nd->path.dentry;
|
||||
case LAST_DOT:
|
||||
if (nd->path.mnt->mnt_sb->s_type->fs_flags & FS_REVAL_DOT) {
|
||||
if (!dir->d_op->d_revalidate(dir, nd)) {
|
||||
error = -ESTALE;
|
||||
@ -1628,7 +1629,6 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
||||
}
|
||||
}
|
||||
/* fallthrough */
|
||||
case LAST_DOT:
|
||||
case LAST_ROOT:
|
||||
if (open_flag & O_CREAT)
|
||||
goto exit;
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include <linux/ncp_fs.h>
|
||||
#include "ncplib_kernel.h"
|
||||
|
||||
static int ncp_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
static int ncp_fsync(struct file *file, int datasync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ static int nfs_link(struct dentry *, struct inode *, struct dentry *);
|
||||
static int nfs_mknod(struct inode *, struct dentry *, int, dev_t);
|
||||
static int nfs_rename(struct inode *, struct dentry *,
|
||||
struct inode *, struct dentry *);
|
||||
static int nfs_fsync_dir(struct file *, struct dentry *, int);
|
||||
static int nfs_fsync_dir(struct file *, int);
|
||||
static loff_t nfs_llseek_dir(struct file *, loff_t, int);
|
||||
|
||||
const struct file_operations nfs_dir_operations = {
|
||||
@ -641,8 +641,10 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
|
||||
* All directory operations under NFS are synchronous, so fsync()
|
||||
* is a dummy operation.
|
||||
*/
|
||||
static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
|
||||
static int nfs_fsync_dir(struct file *filp, int datasync)
|
||||
{
|
||||
struct dentry *dentry = filp->f_path.dentry;
|
||||
|
||||
dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n",
|
||||
dentry->d_parent->d_name.name, dentry->d_name.name,
|
||||
datasync);
|
||||
|
@ -53,7 +53,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
|
||||
static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos);
|
||||
static int nfs_file_flush(struct file *, fl_owner_t id);
|
||||
static int nfs_file_fsync(struct file *, struct dentry *dentry, int datasync);
|
||||
static int nfs_file_fsync(struct file *, int datasync);
|
||||
static int nfs_check_flags(int flags);
|
||||
static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
|
||||
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
|
||||
@ -322,8 +322,9 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
|
||||
* whether any write errors occurred for this process.
|
||||
*/
|
||||
static int
|
||||
nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
nfs_file_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct nfs_open_context *ctx = nfs_file_open_context(file);
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "nilfs.h"
|
||||
#include "segment.h"
|
||||
|
||||
int nilfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
|
||||
int nilfs_sync_file(struct file *file, int datasync)
|
||||
{
|
||||
/*
|
||||
* Called from fsync() system call
|
||||
@ -37,7 +37,7 @@ int nilfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
|
||||
* This function should be implemented when the writeback function
|
||||
* will be implemented.
|
||||
*/
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
int err;
|
||||
|
||||
if (!nilfs_inode_dirty(inode))
|
||||
|
@ -228,7 +228,7 @@ extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *,
|
||||
struct page *, struct inode *);
|
||||
|
||||
/* file.c */
|
||||
extern int nilfs_sync_file(struct file *, struct dentry *, int);
|
||||
extern int nilfs_sync_file(struct file *, int);
|
||||
|
||||
/* ioctl.c */
|
||||
long nilfs_ioctl(struct file *, unsigned int, unsigned long);
|
||||
|
@ -1527,10 +1527,9 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp)
|
||||
* this problem for now. We do write the $BITMAP attribute if it is present
|
||||
* which is the important one for a directory so things are not too bad.
|
||||
*/
|
||||
static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry,
|
||||
int datasync)
|
||||
static int ntfs_dir_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
struct inode *bmp_vi, *vi = dentry->d_inode;
|
||||
struct inode *bmp_vi, *vi = filp->f_mapping->host;
|
||||
int err, ret;
|
||||
ntfs_attr na;
|
||||
|
||||
|
@ -2133,7 +2133,6 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
/**
|
||||
* ntfs_file_fsync - sync a file to disk
|
||||
* @filp: file to be synced
|
||||
* @dentry: dentry describing the file to sync
|
||||
* @datasync: if non-zero only flush user data and not metadata
|
||||
*
|
||||
* Data integrity sync of a file to disk. Used for fsync, fdatasync, and msync
|
||||
@ -2149,19 +2148,15 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
* Also, if @datasync is true, we do not wait on the inode to be written out
|
||||
* but we always wait on the page cache pages to be written out.
|
||||
*
|
||||
* Note: In the past @filp could be NULL so we ignore it as we don't need it
|
||||
* anyway.
|
||||
*
|
||||
* Locking: Caller must hold i_mutex on the inode.
|
||||
*
|
||||
* TODO: We should probably also write all attribute/index inodes associated
|
||||
* with this inode but since we have no simple way of getting to them we ignore
|
||||
* this problem for now.
|
||||
*/
|
||||
static int ntfs_file_fsync(struct file *filp, struct dentry *dentry,
|
||||
int datasync)
|
||||
static int ntfs_file_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
struct inode *vi = dentry->d_inode;
|
||||
struct inode *vi = filp->f_mapping->host;
|
||||
int err, ret = 0;
|
||||
|
||||
ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
|
||||
|
@ -175,13 +175,12 @@ static int ocfs2_dir_release(struct inode *inode, struct file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocfs2_sync_file(struct file *file,
|
||||
struct dentry *dentry,
|
||||
int datasync)
|
||||
static int ocfs2_sync_file(struct file *file, int datasync)
|
||||
{
|
||||
int err = 0;
|
||||
journal_t *journal;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
|
||||
mlog_entry("(0x%p, 0x%p, %d, '%.*s')\n", file, dentry, datasync,
|
||||
@ -1053,7 +1052,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
}
|
||||
|
||||
/*
|
||||
* This will intentionally not wind up calling vmtruncate(),
|
||||
* This will intentionally not wind up calling simple_setsize(),
|
||||
* since all the work for a size change has been done above.
|
||||
* Otherwise, we could get into problems with truncate as
|
||||
* ip_alloc_sem is used there to protect against i_size
|
||||
@ -2119,9 +2118,13 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
|
||||
* direct write may have instantiated a few
|
||||
* blocks outside i_size. Trim these off again.
|
||||
* Don't need i_size_read because we hold i_mutex.
|
||||
*
|
||||
* XXX(hch): this looks buggy because ocfs2 did not
|
||||
* actually implement ->truncate. Take a look at
|
||||
* the new truncate sequence and update this accordingly
|
||||
*/
|
||||
if (*ppos + count > inode->i_size)
|
||||
vmtruncate(inode, inode->i_size);
|
||||
simple_setsize(inode, inode->i_size);
|
||||
ret = written;
|
||||
goto out_dio;
|
||||
}
|
||||
|
@ -329,7 +329,7 @@ const struct file_operations omfs_file_operations = {
|
||||
.aio_read = generic_file_aio_read,
|
||||
.aio_write = generic_file_aio_write,
|
||||
.mmap = generic_file_mmap,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
.splice_read = generic_file_splice_read,
|
||||
};
|
||||
|
||||
|
13
fs/pipe.c
13
fs/pipe.c
@ -1169,14 +1169,18 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
|
||||
switch (cmd) {
|
||||
case F_SETPIPE_SZ:
|
||||
if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages)
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* The pipe needs to be at least 2 pages large to
|
||||
* guarantee POSIX behaviour.
|
||||
*/
|
||||
if (arg < 2)
|
||||
return -EINVAL;
|
||||
if (arg < 2) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = pipe_set_size(pipe, arg);
|
||||
break;
|
||||
case F_GETPIPE_SZ:
|
||||
@ -1187,6 +1191,7 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&pipe->inode->i_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ const struct file_operations qnx4_dir_operations =
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.readdir = qnx4_readdir,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
};
|
||||
|
||||
const struct inode_operations qnx4_dir_inode_operations =
|
||||
|
@ -43,12 +43,13 @@ const struct file_operations ramfs_file_operations = {
|
||||
.write = do_sync_write,
|
||||
.aio_write = generic_file_aio_write,
|
||||
.mmap = generic_file_mmap,
|
||||
.fsync = simple_sync_file,
|
||||
.fsync = noop_fsync,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_write = generic_file_splice_write,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
const struct inode_operations ramfs_file_inode_operations = {
|
||||
.setattr = simple_setattr,
|
||||
.getattr = simple_getattr,
|
||||
};
|
||||
|
@ -42,7 +42,7 @@ const struct file_operations ramfs_file_operations = {
|
||||
.aio_read = generic_file_aio_read,
|
||||
.write = do_sync_write,
|
||||
.aio_write = generic_file_aio_write,
|
||||
.fsync = simple_sync_file,
|
||||
.fsync = noop_fsync,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_write = generic_file_splice_write,
|
||||
.llseek = generic_file_llseek,
|
||||
@ -146,7 +146,7 @@ static int ramfs_nommu_resize(struct inode *inode, loff_t newsize, loff_t size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = vmtruncate(inode, newsize);
|
||||
ret = simple_setsize(inode, newsize);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -169,7 +169,8 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
|
||||
|
||||
/* pick out size-changing events */
|
||||
if (ia->ia_valid & ATTR_SIZE) {
|
||||
loff_t size = i_size_read(inode);
|
||||
loff_t size = inode->i_size;
|
||||
|
||||
if (ia->ia_size != size) {
|
||||
ret = ramfs_nommu_resize(inode, ia->ia_size, size);
|
||||
if (ret < 0 || ia->ia_valid == ATTR_SIZE)
|
||||
@ -182,7 +183,7 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
|
||||
}
|
||||
}
|
||||
|
||||
ret = inode_setattr(inode, ia);
|
||||
generic_setattr(inode, ia);
|
||||
out:
|
||||
ia->ia_valid = old_ia_valid;
|
||||
return ret;
|
||||
|
@ -14,8 +14,7 @@
|
||||
extern const struct reiserfs_key MIN_KEY;
|
||||
|
||||
static int reiserfs_readdir(struct file *, void *, filldir_t);
|
||||
static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
|
||||
int datasync);
|
||||
static int reiserfs_dir_fsync(struct file *filp, int datasync);
|
||||
|
||||
const struct file_operations reiserfs_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
@ -28,10 +27,9 @@ const struct file_operations reiserfs_dir_operations = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
|
||||
int datasync)
|
||||
static int reiserfs_dir_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = filp->f_mapping->host;
|
||||
int err;
|
||||
reiserfs_write_lock(inode->i_sb);
|
||||
err = reiserfs_commit_for_inode(inode);
|
||||
|
@ -134,10 +134,9 @@ static void reiserfs_vfs_truncate_file(struct inode *inode)
|
||||
* be removed...
|
||||
*/
|
||||
|
||||
static int reiserfs_sync_file(struct file *filp,
|
||||
struct dentry *dentry, int datasync)
|
||||
static int reiserfs_sync_file(struct file *filp, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = filp->f_mapping->host;
|
||||
int err;
|
||||
int barrier_done;
|
||||
|
||||
|
@ -28,8 +28,9 @@
|
||||
#include "proto.h"
|
||||
|
||||
static int
|
||||
smb_fsync(struct file *file, struct dentry * dentry, int datasync)
|
||||
smb_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct smb_sb_info *server = server_from_dentry(dentry);
|
||||
int result;
|
||||
|
||||
|
@ -714,7 +714,7 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr)
|
||||
error = server->ops->truncate(inode, attr->ia_size);
|
||||
if (error)
|
||||
goto out;
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
error = simple_setsize(inode, attr->ia_size);
|
||||
if (error)
|
||||
goto out;
|
||||
refresh = 1;
|
||||
|
@ -946,8 +946,8 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
|
||||
EXPORT_SYMBOL_GPL(vfs_kern_mount);
|
||||
|
||||
/**
|
||||
* freeze_super -- lock the filesystem and force it into a consistent state
|
||||
* @super: the super to lock
|
||||
* freeze_super - lock the filesystem and force it into a consistent state
|
||||
* @sb: the super to lock
|
||||
*
|
||||
* Syncs the super to make sure the filesystem is consistent and calls the fs's
|
||||
* freeze_fs. Subsequent calls to this without first thawing the fs will return
|
||||
|
@ -130,12 +130,10 @@ void emergency_sync(void)
|
||||
|
||||
/*
|
||||
* Generic function to fsync a file.
|
||||
*
|
||||
* filp may be NULL if called via the msync of a vma.
|
||||
*/
|
||||
int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
|
||||
int file_fsync(struct file *filp, int datasync)
|
||||
{
|
||||
struct inode * inode = dentry->d_inode;
|
||||
struct inode *inode = filp->f_mapping->host;
|
||||
struct super_block * sb;
|
||||
int ret, err;
|
||||
|
||||
@ -183,7 +181,7 @@ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
* livelocks in fsync_buffers_list().
|
||||
*/
|
||||
mutex_lock(&mapping->host->i_mutex);
|
||||
err = file->f_op->fsync(file, file->f_path.dentry, datasync);
|
||||
err = file->f_op->fsync(file, datasync);
|
||||
if (!ret)
|
||||
ret = err;
|
||||
mutex_unlock(&mapping->host->i_mutex);
|
||||
|
@ -117,13 +117,11 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */
|
||||
|
||||
error = inode_setattr(inode, iattr);
|
||||
if (error)
|
||||
goto out;
|
||||
/* this ignores size changes */
|
||||
generic_setattr(inode, iattr);
|
||||
|
||||
error = sysfs_sd_setattr(sd, iattr);
|
||||
|
||||
out:
|
||||
mutex_unlock(&sysfs_mutex);
|
||||
return error;
|
||||
|
@ -24,7 +24,7 @@ const struct file_operations sysv_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.readdir = sysv_readdir,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
};
|
||||
|
||||
static inline void dir_put_page(struct page *page)
|
||||
|
@ -26,7 +26,7 @@ const struct file_operations sysv_file_operations = {
|
||||
.write = do_sync_write,
|
||||
.aio_write = generic_file_aio_write,
|
||||
.mmap = generic_file_mmap,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
.splice_read = generic_file_splice_read,
|
||||
};
|
||||
|
||||
|
@ -43,6 +43,7 @@ static int sysv_sync_fs(struct super_block *sb, int wait)
|
||||
* then attach current time stamp.
|
||||
* But if the filesystem was marked clean, keep it clean.
|
||||
*/
|
||||
sb->s_dirt = 0;
|
||||
old_time = fs32_to_cpu(sbi, *sbi->s_sb_time);
|
||||
if (sbi->s_type == FSTYPE_SYSV4) {
|
||||
if (*sbi->s_sb_state == cpu_to_fs32(sbi, 0x7c269d38 - old_time))
|
||||
|
@ -967,12 +967,15 @@ static int do_writepage(struct page *page, int len)
|
||||
* the page locked, and it locks @ui_mutex. However, write-back does take inode
|
||||
* @i_mutex, which means other VFS operations may be run on this inode at the
|
||||
* same time. And the problematic one is truncation to smaller size, from where
|
||||
* we have to call 'vmtruncate()', which first changes @inode->i_size, then
|
||||
* we have to call 'simple_setsize()', which first changes @inode->i_size, then
|
||||
* drops the truncated pages. And while dropping the pages, it takes the page
|
||||
* lock. This means that 'do_truncation()' cannot call 'vmtruncate()' with
|
||||
* lock. This means that 'do_truncation()' cannot call 'simple_setsize()' with
|
||||
* @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. This
|
||||
* means that @inode->i_size is changed while @ui_mutex is unlocked.
|
||||
*
|
||||
* XXX: with the new truncate the above is not true anymore, the simple_setsize
|
||||
* calls can be replaced with the individual components.
|
||||
*
|
||||
* But in 'ubifs_writepage()' we have to guarantee that we do not write beyond
|
||||
* inode size. How do we do this if @inode->i_size may became smaller while we
|
||||
* are in the middle of 'ubifs_writepage()'? The UBIFS solution is the
|
||||
@ -1125,7 +1128,7 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
|
||||
budgeted = 0;
|
||||
}
|
||||
|
||||
err = vmtruncate(inode, new_size);
|
||||
err = simple_setsize(inode, new_size);
|
||||
if (err)
|
||||
goto out_budg;
|
||||
|
||||
@ -1214,7 +1217,7 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
|
||||
|
||||
if (attr->ia_valid & ATTR_SIZE) {
|
||||
dbg_gen("size %lld -> %lld", inode->i_size, new_size);
|
||||
err = vmtruncate(inode, new_size);
|
||||
err = simple_setsize(inode, new_size);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
@ -1223,7 +1226,7 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
|
||||
if (attr->ia_valid & ATTR_SIZE) {
|
||||
/* Truncation changes inode [mc]time */
|
||||
inode->i_mtime = inode->i_ctime = ubifs_current_time(inode);
|
||||
/* 'vmtruncate()' changed @i_size, update @ui_size */
|
||||
/* 'simple_setsize()' changed @i_size, update @ui_size */
|
||||
ui->ui_size = inode->i_size;
|
||||
}
|
||||
|
||||
@ -1304,9 +1307,9 @@ static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
||||
int ubifs_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct ubifs_info *c = inode->i_sb->s_fs_info;
|
||||
int err;
|
||||
|
||||
|
@ -379,7 +379,7 @@ struct ubifs_gced_idx_leb {
|
||||
* The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses
|
||||
* @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot
|
||||
* make sure @inode->i_size is always changed under @ui_mutex, because it
|
||||
* cannot call 'vmtruncate()' with @ui_mutex locked, because it would deadlock
|
||||
* cannot call 'simple_setsize()' with @ui_mutex locked, because it would deadlock
|
||||
* with 'ubifs_writepage()' (see file.c). All the other inode fields are
|
||||
* changed under @ui_mutex, so they do not need "shadow" fields. Note, one
|
||||
* could consider to rework locking and base it on "shadow" fields.
|
||||
@ -1678,7 +1678,7 @@ const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c);
|
||||
int ubifs_calc_dark(const struct ubifs_info *c, int spc);
|
||||
|
||||
/* file.c */
|
||||
int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync);
|
||||
int ubifs_fsync(struct file *file, int datasync);
|
||||
int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
|
||||
/* dir.c */
|
||||
|
@ -211,5 +211,5 @@ const struct file_operations udf_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = udf_readdir,
|
||||
.unlocked_ioctl = udf_ioctl,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
};
|
||||
|
@ -224,7 +224,7 @@ const struct file_operations udf_file_operations = {
|
||||
.write = do_sync_write,
|
||||
.aio_write = udf_file_aio_write,
|
||||
.release = udf_release_file,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
@ -666,6 +666,6 @@ int ufs_empty_dir(struct inode * inode)
|
||||
const struct file_operations ufs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = ufs_readdir,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
@ -42,6 +42,6 @@ const struct file_operations ufs_file_operations = {
|
||||
.aio_write = generic_file_aio_write,
|
||||
.mmap = generic_file_mmap,
|
||||
.open = dquot_file_open,
|
||||
.fsync = simple_fsync,
|
||||
.fsync = generic_file_fsync,
|
||||
.splice_read = generic_file_splice_read,
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user