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 16static int 17nfsd4_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 38static __be32 39nfsd4_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 47static __be32 48nfsd4_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 if (seg->offset & (block_size - 1)) { 60 dprintk("pnfsd: I/O misaligned\n"); 61 goto out_layoutunavailable; 62 } 63 64 /* 65 * Some clients barf on non-zero block numbers for NONE or INVALID 66 * layouts, so make sure to zero the whole structure. 67 */ 68 error = -ENOMEM; 69 bex = kzalloc(sizeof(*bex), GFP_KERNEL); 70 if (!bex) 71 goto out_error; 72 args->lg_content = bex; 73 74 error = sb->s_export_op->map_blocks(inode, seg->offset, seg->length, 75 &iomap, seg->iomode != IOMODE_READ, 76 &device_generation); 77 if (error) { 78 if (error == -ENXIO) 79 goto out_layoutunavailable; 80 goto out_error; 81 } 82 83 if (iomap.length < args->lg_minlength) { 84 dprintk("pnfsd: extent smaller than minlength\n"); 85 goto out_layoutunavailable; 86 } 87 88 switch (iomap.type) { 89 case IOMAP_MAPPED: 90 if (seg->iomode == IOMODE_READ) 91 bex->es = PNFS_BLOCK_READ_DATA; 92 else 93 bex->es = PNFS_BLOCK_READWRITE_DATA; 94 bex->soff = (iomap.blkno << 9); 95 break; 96 case IOMAP_UNWRITTEN: 97 if (seg->iomode & IOMODE_RW) { 98 /* 99 * Crack monkey special case from section 2.3.1. 100 */ 101 if (args->lg_minlength == 0) { 102 dprintk("pnfsd: no soup for you!\n"); 103 goto out_layoutunavailable; 104 } 105 106 bex->es = PNFS_BLOCK_INVALID_DATA; 107 bex->soff = (iomap.blkno << 9); 108 break; 109 } 110 /*FALLTHRU*/ 111 case IOMAP_HOLE: 112 if (seg->iomode == IOMODE_READ) { 113 bex->es = PNFS_BLOCK_NONE_DATA; 114 break; 115 } 116 /*FALLTHRU*/ 117 case IOMAP_DELALLOC: 118 default: 119 WARN(1, "pnfsd: filesystem returned %d extent\n", iomap.type); 120 goto out_layoutunavailable; 121 } 122 123 error = nfsd4_set_deviceid(&bex->vol_id, fhp, device_generation); 124 if (error) 125 goto out_error; 126 bex->foff = iomap.offset; 127 bex->len = iomap.length; 128 129 seg->offset = iomap.offset; 130 seg->length = iomap.length; 131 132 dprintk("GET: 0x%llx:0x%llx %d\n", bex->foff, bex->len, bex->es); 133 return 0; 134 135out_error: 136 seg->length = 0; 137 return nfserrno(error); 138out_layoutunavailable: 139 seg->length = 0; 140 return nfserr_layoutunavailable; 141} 142 143static __be32 144nfsd4_block_proc_layoutcommit(struct inode *inode, 145 struct nfsd4_layoutcommit *lcp) 146{ 147 loff_t new_size = lcp->lc_last_wr + 1; 148 struct iattr iattr = { .ia_valid = 0 }; 149 struct iomap *iomaps; 150 int nr_iomaps; 151 int error; 152 153 nr_iomaps = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout, 154 lcp->lc_up_len, &iomaps, 1 << inode->i_blkbits); 155 if (nr_iomaps < 0) 156 return nfserrno(nr_iomaps); 157 158 if (lcp->lc_mtime.tv_nsec == UTIME_NOW || 159 timespec_compare(&lcp->lc_mtime, &inode->i_mtime) < 0) 160 lcp->lc_mtime = current_fs_time(inode->i_sb); 161 iattr.ia_valid |= ATTR_ATIME | ATTR_CTIME | ATTR_MTIME; 162 iattr.ia_atime = iattr.ia_ctime = iattr.ia_mtime = lcp->lc_mtime; 163 164 if (new_size > i_size_read(inode)) { 165 iattr.ia_valid |= ATTR_SIZE; 166 iattr.ia_size = new_size; 167 } 168 169 error = inode->i_sb->s_export_op->commit_blocks(inode, iomaps, 170 nr_iomaps, &iattr); 171 kfree(iomaps); 172 return nfserrno(error); 173} 174 175const struct nfsd4_layout_ops bl_layout_ops = { 176 /* 177 * Pretend that we send notification to the client. This is a blatant 178 * lie to force recent Linux clients to cache our device IDs. 179 * We rarely ever change the device ID, so the harm of leaking deviceids 180 * for a while isn't too bad. Unfortunately RFC5661 is a complete mess 181 * in this regard, but I filed errata 4119 for this a while ago, and 182 * hopefully the Linux client will eventually start caching deviceids 183 * without this again. 184 */ 185 .notify_types = 186 NOTIFY_DEVICEID4_DELETE | NOTIFY_DEVICEID4_CHANGE, 187 .proc_getdeviceinfo = nfsd4_block_proc_getdeviceinfo, 188 .encode_getdeviceinfo = nfsd4_block_encode_getdeviceinfo, 189 .proc_layoutget = nfsd4_block_proc_layoutget, 190 .encode_layoutget = nfsd4_block_encode_layoutget, 191 .proc_layoutcommit = nfsd4_block_proc_layoutcommit, 192}; 193