diff -urNp --exclude CVS --exclude BitKeeper x-ref/fs/fcntl.c x/fs/fcntl.c --- x-ref/fs/fcntl.c 2003-07-17 03:29:54.000000000 +0200 +++ x/fs/fcntl.c 2003-07-17 03:43:15.000000000 +0200 @@ -231,6 +231,11 @@ static int setfl(int fd, struct file * f } if (arg & O_DIRECT) { + error = -EINVAL; + if (!inode->i_mapping || !inode->i_mapping->a_ops || + !have_mapping_directIO(inode->i_mapping)) + goto out; + if (!filp->f_iobuf) { error = alloc_kiovec(1, &filp->f_iobuf); if (error < 0) diff -urNp --exclude CVS --exclude BitKeeper x-ref/fs/open.c x/fs/open.c --- x-ref/fs/open.c 2003-07-15 02:05:51.000000000 +0200 +++ x/fs/open.c 2003-07-17 03:42:44.000000000 +0200 @@ -701,6 +701,12 @@ struct file *dentry_open(struct dentry * } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); + /* NB: we're sure to have correct a_ops only after f_op->open */ + error = -EINVAL; + if (f->f_flags & O_DIRECT && (!inode->i_mapping || !inode->i_mapping->a_ops || + !have_mapping_directIO(inode->i_mapping))) + goto cleanup_all; + return f; cleanup_all: diff -urNp --exclude CVS --exclude BitKeeper x-ref/include/linux/fs.h x/include/linux/fs.h --- x-ref/include/linux/fs.h 2003-07-17 03:29:52.000000000 +0200 +++ x/include/linux/fs.h 2003-07-17 03:42:45.000000000 +0200 @@ -519,6 +519,11 @@ struct inode { } u; }; +static inline int have_mapping_directIO(struct address_space * mapping) +{ + return mapping->a_ops->direct_IO || mapping->a_ops->direct_fileIO; +} + static inline void inode_add_bytes(struct inode *inode, loff_t bytes) { inode->i_blocks += bytes >> 9; diff -urNp --exclude CVS --exclude BitKeeper x-ref/mm/filemap.c x/mm/filemap.c --- x-ref/mm/filemap.c 2003-07-17 03:29:56.000000000 +0200 +++ x/mm/filemap.c 2003-07-17 03:40:38.000000000 +0200 @@ -1522,11 +1522,6 @@ no_cached_page: UPDATE_ATIME(inode); } -static inline int have_mapping_directIO(struct address_space * mapping) -{ - return mapping->a_ops->direct_IO || mapping->a_ops->direct_fileIO; -} - /* Switch between old and new directIO formats */ static inline int do_call_directIO(int rw, struct file *filp, struct kiobuf *iobuf, unsigned long offset, int blocksize) { @@ -1573,8 +1568,6 @@ static ssize_t generic_file_direct_IO(in retval = -EINVAL; if ((offset & blocksize_mask) || (count & blocksize_mask) || ((unsigned long) buf & blocksize_mask)) goto out_free; - if (!have_mapping_directIO(mapping)) - goto out_free; if ((rw == READ) && (offset + count > size)) count = size - offset;