]> Git Repo - linux.git/blobdiff - fs/cifs/smb2ops.c
cifs: add fiemap support
[linux.git] / fs / cifs / smb2ops.c
index 4002e1433ccbada803e808fa74918706a19fa64c..78bca7d46eac4f4ab2f1697e46a9ade26b2c8ff4 100644 (file)
@@ -2886,6 +2886,79 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
        return rc;
 }
 
+static int smb3_fiemap(struct cifs_tcon *tcon,
+                      struct cifsFileInfo *cfile,
+                      struct fiemap_extent_info *fei, u64 start, u64 len)
+{
+       unsigned int xid;
+       struct file_allocated_range_buffer in_data, *out_data;
+       u32 out_data_len;
+       int i, num, rc, flags, last_blob;
+       u64 next;
+
+       if (fiemap_check_flags(fei, FIEMAP_FLAG_SYNC))
+               return -EBADR;
+
+       xid = get_xid();
+ again:
+       in_data.file_offset = cpu_to_le64(start);
+       in_data.length = cpu_to_le64(len);
+
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid,
+                       FSCTL_QUERY_ALLOCATED_RANGES, true,
+                       (char *)&in_data, sizeof(in_data),
+                       1024 * sizeof(struct file_allocated_range_buffer),
+                       (char **)&out_data, &out_data_len);
+       if (rc == -E2BIG) {
+               last_blob = 0;
+               rc = 0;
+       } else
+               last_blob = 1;
+       if (rc)
+               goto out;
+
+       if (out_data_len < sizeof(struct file_allocated_range_buffer)) {
+               rc = -EINVAL;
+               goto out;
+       }
+       if (out_data_len % sizeof(struct file_allocated_range_buffer)) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       num = out_data_len / sizeof(struct file_allocated_range_buffer);
+       for (i = 0; i < num; i++) {
+               flags = 0;
+               if (i == num - 1 && last_blob)
+                       flags |= FIEMAP_EXTENT_LAST;
+
+               rc = fiemap_fill_next_extent(fei,
+                               le64_to_cpu(out_data[i].file_offset),
+                               le64_to_cpu(out_data[i].file_offset),
+                               le64_to_cpu(out_data[i].length),
+                               flags);
+               if (rc < 0)
+                       goto out;
+               if (rc == 1) {
+                       rc = 0;
+                       goto out;
+               }
+       }
+
+       if (!last_blob) {
+               next = le64_to_cpu(out_data[num - 1].file_offset) +
+                 le64_to_cpu(out_data[num - 1].length);
+               len = len - (next - start);
+               start = next;
+               goto again;
+       }
+
+ out:
+       free_xid(xid);
+       kfree(out_data);
+       return rc;
+}
 
 static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
                           loff_t off, loff_t len)
@@ -4054,6 +4127,7 @@ struct smb_version_operations smb20_operations = {
        .next_header = smb2_next_header,
        .ioctl_query_info = smb2_ioctl_query_info,
        .make_node = smb2_make_node,
+       .fiemap = smb3_fiemap,
 };
 
 struct smb_version_operations smb21_operations = {
@@ -4153,6 +4227,7 @@ struct smb_version_operations smb21_operations = {
        .next_header = smb2_next_header,
        .ioctl_query_info = smb2_ioctl_query_info,
        .make_node = smb2_make_node,
+       .fiemap = smb3_fiemap,
 };
 
 struct smb_version_operations smb30_operations = {
@@ -4261,6 +4336,7 @@ struct smb_version_operations smb30_operations = {
        .next_header = smb2_next_header,
        .ioctl_query_info = smb2_ioctl_query_info,
        .make_node = smb2_make_node,
+       .fiemap = smb3_fiemap,
 };
 
 struct smb_version_operations smb311_operations = {
@@ -4370,6 +4446,7 @@ struct smb_version_operations smb311_operations = {
        .next_header = smb2_next_header,
        .ioctl_query_info = smb2_ioctl_query_info,
        .make_node = smb2_make_node,
+       .fiemap = smb3_fiemap,
 };
 
 struct smb_version_values smb20_values = {
This page took 0.038968 seconds and 4 git commands to generate.