X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzpl_file.c;h=9c27b7f1d3b2f614a0e996f980da858780ab8548;hb=30b92c1de68ced4bee235f879791ee316314a197;hp=0ef2c1558f0b38dc9c010dddf217e75f03aeabc3;hpb=adcd70bd1af405464d6dbc6b2057594cddda7a24;p=zfs.git diff --git a/module/zfs/zpl_file.c b/module/zfs/zpl_file.c index 0ef2c15..9c27b7f 100644 --- a/module/zfs/zpl_file.c +++ b/module/zfs/zpl_file.c @@ -357,21 +357,16 @@ zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data) ASSERT(PageLocked(pp)); ASSERT(!PageWriteback(pp)); + ASSERT(!(current->flags & PF_NOFS)); /* - * Disable the normal reclaim path for zpl_putpage(). This - * ensures that all memory allocations under this call path - * will never enter direct reclaim. If this were to happen - * the VM might try to write out additional pages by calling - * zpl_putpage() again resulting in a deadlock. + * Annotate this call path with a flag that indicates that it is + * unsafe to use KM_SLEEP during memory allocations due to the + * potential for a deadlock. KM_PUSHPAGE should be used instead. */ - if (current->flags & PF_MEMALLOC) { - (void) zfs_putpage(mapping->host, pp, wbc); - } else { - current->flags |= PF_MEMALLOC; - (void) zfs_putpage(mapping->host, pp, wbc); - current->flags &= ~PF_MEMALLOC; - } + current->flags |= PF_NOFS; + (void) zfs_putpage(mapping->host, pp, wbc); + current->flags &= ~PF_NOFS; return (0); } @@ -394,6 +389,50 @@ zpl_writepage(struct page *pp, struct writeback_control *wbc) return zpl_putpage(pp, wbc, pp->mapping); } +/* + * The only flag combination which matches the behavior of zfs_space() + * is FALLOC_FL_PUNCH_HOLE. This flag was introduced in the 2.6.38 kernel. + */ +long +zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len) +{ + cred_t *cr = CRED(); + int error = -EOPNOTSUPP; + + if (mode & FALLOC_FL_KEEP_SIZE) + return (-EOPNOTSUPP); + + crhold(cr); + +#ifdef FALLOC_FL_PUNCH_HOLE + if (mode & FALLOC_FL_PUNCH_HOLE) { + flock64_t bf; + + bf.l_type = F_WRLCK; + bf.l_whence = 0; + bf.l_start = offset; + bf.l_len = len; + bf.l_pid = 0; + + error = -zfs_space(ip, F_FREESP, &bf, FWRITE, offset, cr); + } +#endif /* FALLOC_FL_PUNCH_HOLE */ + + crfree(cr); + + ASSERT3S(error, <=, 0); + return (error); +} + +#ifdef HAVE_FILE_FALLOCATE +static long +zpl_fallocate(struct file *filp, int mode, loff_t offset, loff_t len) +{ + return zpl_fallocate_common(filp->f_path.dentry->d_inode, + mode, offset, len); +} +#endif /* HAVE_FILE_FALLOCATE */ + const struct address_space_operations zpl_address_space_operations = { .readpages = zpl_readpages, .readpage = zpl_readpage, @@ -410,6 +449,9 @@ const struct file_operations zpl_file_operations = { .readdir = zpl_readdir, .mmap = zpl_mmap, .fsync = zpl_fsync, +#ifdef HAVE_FILE_FALLOCATE + .fallocate = zpl_fallocate, +#endif /* HAVE_FILE_FALLOCATE */ }; const struct file_operations zpl_dir_file_operations = {