#include <linux/smp_lock.h>
static struct vm_operations_struct xfs_file_vm_ops;
-#ifdef CONFIG_XFS_DMAPI
-static struct vm_operations_struct xfs_dmapi_file_vm_ops;
-#endif
STATIC_INLINE ssize_t
__xfs_file_read(
return -xfs_release(XFS_I(inode));
}
+/*
+ * We ignore the datasync flag here because a datasync is effectively
+ * identical to an fsync. That is, datasync implies that we need to write
+ * only the metadata needed to be able to access the data that is written
+ * if we crash after the call completes. Hence if we are writing beyond
+ * EOF we have to log the inode size change as well, which makes it a
+ * full fsync. If we don't write beyond EOF, the inode core will be
+ * clean in memory and so we don't need to log the inode, just like
+ * fsync.
+ */
STATIC int
xfs_file_fsync(
struct file *filp,
struct dentry *dentry,
int datasync)
{
- int flags = FSYNC_WAIT;
-
- if (datasync)
- flags |= FSYNC_DATA;
xfs_iflags_clear(XFS_I(dentry->d_inode), XFS_ITRUNCATED);
- return -xfs_fsync(XFS_I(dentry->d_inode), flags,
- (xfs_off_t)0, (xfs_off_t)-1);
+ return -xfs_fsync(XFS_I(dentry->d_inode));
}
-#ifdef CONFIG_XFS_DMAPI
-STATIC int
-xfs_vm_fault(
- struct vm_area_struct *vma,
- struct vm_fault *vmf)
-{
- struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
- bhv_vnode_t *vp = vn_from_inode(inode);
-
- ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
- if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), vma, 0))
- return VM_FAULT_SIGBUS;
- return filemap_fault(vma, vmf);
-}
-#endif /* CONFIG_XFS_DMAPI */
-
+/*
+ * Unfortunately we can't just use the clean and simple readdir implementation
+ * below, because nfs might call back into ->lookup from the filldir callback
+ * and that will deadlock the low-level btree code.
+ *
+ * Hopefully we'll find a better workaround that allows to use the optimal
+ * version at least for local readdirs for 2.6.25.
+ */
+#if 0
STATIC int
xfs_file_readdir(
struct file *filp,
return -error;
return 0;
}
+#else
+
+struct hack_dirent {
+ u64 ino;
+ loff_t offset;
+ int namlen;
+ unsigned int d_type;
+ char name[];
+};
+
+struct hack_callback {
+ char *dirent;
+ size_t len;
+ size_t used;
+};
+
+STATIC int
+xfs_hack_filldir(
+ void *__buf,
+ const char *name,
+ int namlen,
+ loff_t offset,
+ u64 ino,
+ unsigned int d_type)
+{
+ struct hack_callback *buf = __buf;
+ struct hack_dirent *de = (struct hack_dirent *)(buf->dirent + buf->used);
+ unsigned int reclen;
+
+ reclen = ALIGN(sizeof(struct hack_dirent) + namlen, sizeof(u64));
+ if (buf->used + reclen > buf->len)
+ return -EINVAL;
+
+ de->namlen = namlen;
+ de->offset = offset;
+ de->ino = ino;
+ de->d_type = d_type;
+ memcpy(de->name, name, namlen);
+ buf->used += reclen;
+ return 0;
+}
+
+STATIC int
+xfs_file_readdir(
+ struct file *filp,
+ void *dirent,
+ filldir_t filldir)
+{
+ struct inode *inode = filp->f_path.dentry->d_inode;
+ xfs_inode_t *ip = XFS_I(inode);
+ struct hack_callback buf;
+ struct hack_dirent *de;
+ int error;
+ loff_t size;
+ int eof = 0;
+ xfs_off_t start_offset, curr_offset, offset;
+
+ /*
+ * Try fairly hard to get memory
+ */
+ buf.len = PAGE_CACHE_SIZE;
+ do {
+ buf.dirent = kmalloc(buf.len, GFP_KERNEL);
+ if (buf.dirent)
+ break;
+ buf.len >>= 1;
+ } while (buf.len >= 1024);
+
+ if (!buf.dirent)
+ return -ENOMEM;
+
+ curr_offset = filp->f_pos;
+ if (curr_offset == 0x7fffffff)
+ offset = 0xffffffff;
+ else
+ offset = filp->f_pos;
+
+ while (!eof) {
+ unsigned int reclen;
+
+ start_offset = offset;
+
+ buf.used = 0;
+ error = -xfs_readdir(ip, &buf, buf.len, &offset,
+ xfs_hack_filldir);
+ if (error || offset == start_offset) {
+ size = 0;
+ break;
+ }
+
+ size = buf.used;
+ de = (struct hack_dirent *)buf.dirent;
+ while (size > 0) {
+ curr_offset = de->offset /* & 0x7fffffff */;
+ if (filldir(dirent, de->name, de->namlen,
+ curr_offset & 0x7fffffff,
+ de->ino, de->d_type)) {
+ goto done;
+ }
+
+ reclen = ALIGN(sizeof(struct hack_dirent) + de->namlen,
+ sizeof(u64));
+ size -= reclen;
+ de = (struct hack_dirent *)((char *)de + reclen);
+ }
+ }
+
+ done:
+ if (!error) {
+ if (size == 0)
+ filp->f_pos = offset & 0x7fffffff;
+ else if (de)
+ filp->f_pos = curr_offset;
+ }
+
+ kfree(buf.dirent);
+ return error;
+}
+#endif
STATIC int
xfs_file_mmap(
vma->vm_ops = &xfs_file_vm_ops;
vma->vm_flags |= VM_CAN_NONLINEAR;
-#ifdef CONFIG_XFS_DMAPI
- if (XFS_M(filp->f_path.dentry->d_inode->i_sb)->m_flags & XFS_MOUNT_DMAPI)
- vma->vm_ops = &xfs_dmapi_file_vm_ops;
-#endif /* CONFIG_XFS_DMAPI */
-
file_accessed(filp);
return 0;
}
return error;
}
-#ifdef CONFIG_XFS_DMAPI
-#ifdef HAVE_VMOP_MPROTECT
-STATIC int
-xfs_vm_mprotect(
- struct vm_area_struct *vma,
- unsigned int newflags)
-{
- struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
- struct xfs_mount *mp = XFS_M(inode->i_sb);
- int error = 0;
-
- if (mp->m_flags & XFS_MOUNT_DMAPI) {
- if ((vma->vm_flags & VM_MAYSHARE) &&
- (newflags & VM_WRITE) && !(vma->vm_flags & VM_WRITE))
- error = XFS_SEND_MMAP(mp, vma, VM_WRITE);
- }
- return error;
-}
-#endif /* HAVE_VMOP_MPROTECT */
-#endif /* CONFIG_XFS_DMAPI */
-
-#ifdef HAVE_FOP_OPEN_EXEC
-/* If the user is attempting to execute a file that is offline then
- * we have to trigger a DMAPI READ event before the file is marked as busy
- * otherwise the invisible I/O will not be able to write to the file to bring
- * it back online.
- */
-STATIC int
-xfs_file_open_exec(
- struct inode *inode)
-{
- struct xfs_mount *mp = XFS_M(inode->i_sb);
-
- if (unlikely(mp->m_flags & XFS_MOUNT_DMAPI)) {
- if (DM_EVENT_ENABLED(XFS_I(inode), DM_EVENT_READ)) {
- bhv_vnode_t *vp = vn_from_inode(inode);
-
- return -XFS_SEND_DATA(mp, DM_EVENT_READ,
- vp, 0, 0, 0, NULL);
- }
- }
-
- return 0;
-}
-#endif /* HAVE_FOP_OPEN_EXEC */
-
/*
* mmap()d file has taken write protection fault and is being made
* writable. We can set the page state up correctly for a writable
.fault = filemap_fault,
.page_mkwrite = xfs_vm_page_mkwrite,
};
-
-#ifdef CONFIG_XFS_DMAPI
-static struct vm_operations_struct xfs_dmapi_file_vm_ops = {
- .fault = xfs_vm_fault,
- .page_mkwrite = xfs_vm_page_mkwrite,
-#ifdef HAVE_VMOP_MPROTECT
- .mprotect = xfs_vm_mprotect,
-#endif
-};
-#endif /* CONFIG_XFS_DMAPI */