1 /* 2 * Copyright (c) 2014 Christoph Hellwig. 3 */ 4 #include <linux/exportfs.h> 5 #include <linux/genhd.h> 6 #include <linux/slab.h> 7 8 #include <linux/nfsd/debug.h> 9 10 #include "blocklayoutxdr.h" 11 #include "pnfs.h" 12 13 #define NFSDDBG_FACILITY NFSDDBG_PNFS 14 15 16 static int 17 nfsd4_block_get_device_info_simple(struct super_block *sb, 18 struct nfsd4_getdeviceinfo *gdp) 19 { 20 struct pnfs_block_deviceaddr *dev; 21 struct pnfs_block_volume *b; 22 23 dev = kzalloc(sizeof(struct pnfs_block_deviceaddr) + 24 sizeof(struct pnfs_block_volume), GFP_KERNEL); 25 if (!dev) 26 return -ENOMEM; 27 gdp->gd_device = dev; 28 29 dev->nr_volumes = 1; 30 b = &dev->volumes[0]; 31 32 b->type = PNFS_BLOCK_VOLUME_SIMPLE; 33 b->simple.sig_len = PNFS_BLOCK_UUID_LEN; 34 return sb->s_export_op->get_uuid(sb, b->simple.sig, &b->simple.sig_len, 35 &b->simple.offset); 36 } 37 38 static __be32 39 nfsd4_block_proc_getdeviceinfo(struct super_block *sb, 40 struct nfsd4_getdeviceinfo *gdp) 41 { 42 if (sb->s_bdev != sb->s_bdev->bd_contains) 43 return nfserr_inval; 44 return nfserrno(nfsd4_block_get_device_info_simple(sb, gdp)); 45 } 46 47 static __be32 48 nfsd4_block_proc_layoutget(struct inode *inode, const struct svc_fh *fhp, 49 struct nfsd4_layoutget *args) 50 { 51 struct nfsd4_layout_seg *seg = &args->lg_seg; 52 struct super_block *sb = inode->i_sb; 53 u32 block_size = (1 << inode->i_blkbits); 54 struct pnfs_block_extent *bex; 55 struct iomap iomap; 56 u32 device_generation = 0; 57 int error; 58 59 /* 60 * We do not attempt to support I/O smaller than the fs block size, 61 * or not aligned to it. 62 */ 63 if (args->lg_minlength < block_size) { 64 dprintk("pnfsd: I/O too small\n"); 65 goto out_layoutunavailable; 66 } 67 if (seg->offset & (block_size - 1)) { 68 dprintk("pnfsd: I/O misaligned\n"); 69 goto out_layoutunavailable; 70 } 71 72 /* 73 * Some clients barf on non-zero block numbers for NONE or INVALID 74 * layouts, so make sure to zero the whole structure. 75 */ 76 error = -ENOMEM; 77 bex = kzalloc(sizeof(*bex), GFP_KERNEL); 78 if (!bex) 79 goto out_error; 80 args->lg_content = bex; 81 82 error = sb->s_export_op->map_blocks(inode, seg->offset, seg->length, 83 &iomap, seg->iomode != IOMODE_READ, 84 &device_generation); 85 if (error) { 86 if (error == -ENXIO) 87 goto out_layoutunavailable; 88 goto out_error; 89 } 90 91 if (iomap.length < args->lg_minlength) { 92 dprintk("pnfsd: extent smaller than minlength\n"); 93 goto out_layoutunavailable; 94 } 95 96 switch (iomap.type) { 97 case IOMAP_MAPPED: 98 if (seg->iomode == IOMODE_READ) 99 bex->es = PNFS_BLOCK_READ_DATA; 100 else 101 bex->es = PNFS_BLOCK_READWRITE_DATA; 102 bex->soff = (iomap.blkno << 9); 103 break; 104 case IOMAP_UNWRITTEN: 105 if (seg->iomode & IOMODE_RW) { 106 /* 107 * Crack monkey special case from section 2.3.1. 108 */ 109 if (args->lg_minlength == 0) { 110 dprintk("pnfsd: no soup for you!\n"); 111 goto out_layoutunavailable; 112 } 113 114 bex->es = PNFS_BLOCK_INVALID_DATA; 115 bex->soff = (iomap.blkno << 9); 116 break; 117 } 118 /*FALLTHRU*/ 119 case IOMAP_HOLE: 120 if (seg->iomode == IOMODE_READ) { 121 bex->es = PNFS_BLOCK_NONE_DATA; 122 break; 123 } 124 /*FALLTHRU*/ 125 case IOMAP_DELALLOC: 126 default: 127 WARN(1, "pnfsd: filesystem returned %d extent\n", iomap.type); 128 goto out_layoutunavailable; 129 } 130 131 error = nfsd4_set_deviceid(&bex->vol_id, fhp, device_generation); 132 if (error) 133 goto out_error; 134 bex->foff = iomap.offset; 135 bex->len = iomap.length; 136 137 seg->offset = iomap.offset; 138 seg->length = iomap.length; 139 140 dprintk("GET: 0x%llx:0x%llx %d\n", bex->foff, bex->len, bex->es); 141 return 0; 142 143 out_error: 144 seg->length = 0; 145 return nfserrno(error); 146 out_layoutunavailable: 147 seg->length = 0; 148 return nfserr_layoutunavailable; 149 } 150 151 static __be32 152 nfsd4_block_proc_layoutcommit(struct inode *inode, 153 struct nfsd4_layoutcommit *lcp) 154 { 155 loff_t new_size = lcp->lc_last_wr + 1; 156 struct iattr iattr = { .ia_valid = 0 }; 157 struct iomap *iomaps; 158 int nr_iomaps; 159 int error; 160 161 nr_iomaps = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout, 162 lcp->lc_up_len, &iomaps, 1 << inode->i_blkbits); 163 if (nr_iomaps < 0) 164 return nfserrno(nr_iomaps); 165 166 if (lcp->lc_mtime.tv_nsec == UTIME_NOW || 167 timespec_compare(&lcp->lc_mtime, &inode->i_mtime) < 0) 168 lcp->lc_mtime = current_fs_time(inode->i_sb); 169 iattr.ia_valid |= ATTR_ATIME | ATTR_CTIME | ATTR_MTIME; 170 iattr.ia_atime = iattr.ia_ctime = iattr.ia_mtime = lcp->lc_mtime; 171 172 if (new_size > i_size_read(inode)) { 173 iattr.ia_valid |= ATTR_SIZE; 174 iattr.ia_size = new_size; 175 } 176 177 error = inode->i_sb->s_export_op->commit_blocks(inode, iomaps, 178 nr_iomaps, &iattr); 179 kfree(iomaps); 180 return nfserrno(error); 181 } 182 183 const struct nfsd4_layout_ops bl_layout_ops = { 184 .proc_getdeviceinfo = nfsd4_block_proc_getdeviceinfo, 185 .encode_getdeviceinfo = nfsd4_block_encode_getdeviceinfo, 186 .proc_layoutget = nfsd4_block_proc_layoutget, 187 .encode_layoutget = nfsd4_block_encode_layoutget, 188 .proc_layoutcommit = nfsd4_block_proc_layoutcommit, 189 }; 190