diff -druN Linux-2.4.19-pre3/fs/fcntl.c linux-2.4.19-pre3/fs/fcntl.c --- Linux-2.4.19-pre3/fs/fcntl.c Wed Mar 13 12:30:42 2002 +++ linux-2.4.19-pre3/fs/fcntl.c Thu Mar 21 10:33:10 2002 @@ -219,6 +219,11 @@ } if (arg & O_DIRECT) { + if (inode->i_mapping && inode->i_mapping->a_ops) { + if (!inode->i_mapping->a_ops->direct_IO) + return -EINVAL; + } + /* * alloc_kiovec() can sleep and we are only serialized by * the big kernel lock here, so abuse the i_sem to serialize diff -druN Linux-2.4.19-pre3/fs/open.c linux-2.4.19-pre3/fs/open.c --- Linux-2.4.19-pre3/fs/open.c Wed Mar 13 12:31:10 2002 +++ linux-2.4.19-pre3/fs/open.c Thu Mar 21 10:31:32 2002 @@ -691,6 +691,14 @@ } 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 */ + if (f->f_flags & O_DIRECT) { + error = -EINVAL; + if (inode->i_mapping && inode->i_mapping->a_ops) + if (!inode->i_mapping->a_ops->direct_IO) + goto cleanup_all; + } + return f; cleanup_all: diff -druN Linux-2.4.19-pre3/mm/filemap.c linux-2.4.19-pre3/mm/filemap.c --- Linux-2.4.19-pre3/mm/filemap.c Wed Mar 13 12:32:01 2002 +++ linux-2.4.19-pre3/mm/filemap.c Thu Mar 21 10:13:09 2002 @@ -1562,8 +1562,6 @@ retval = -EINVAL; if ((offset & blocksize_mask) || (count & blocksize_mask)) goto out_free; - if (!mapping->a_ops->direct_IO) - goto out_free; /* * Flush to disk exclusively the _data_, metadata must remain