diff options
-rw-r--r-- | fs/cifs/smb2ops.c | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index c5f521bcdee2..568f323665c8 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -1102,6 +1102,64 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, | |||
1102 | return rc; | 1102 | return rc; |
1103 | } | 1103 | } |
1104 | 1104 | ||
1105 | static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, | ||
1106 | loff_t off, loff_t len, bool keep_size) | ||
1107 | { | ||
1108 | struct inode *inode; | ||
1109 | struct cifsInodeInfo *cifsi; | ||
1110 | struct cifsFileInfo *cfile = file->private_data; | ||
1111 | long rc = -EOPNOTSUPP; | ||
1112 | unsigned int xid; | ||
1113 | |||
1114 | xid = get_xid(); | ||
1115 | |||
1116 | inode = cfile->dentry->d_inode; | ||
1117 | cifsi = CIFS_I(inode); | ||
1118 | |||
1119 | /* if file not oplocked can't be sure whether asking to extend size */ | ||
1120 | if (!CIFS_CACHE_READ(cifsi)) | ||
1121 | if (keep_size == false) | ||
1122 | return -EOPNOTSUPP; | ||
1123 | |||
1124 | /* | ||
1125 | * Files are non-sparse by default so falloc may be a no-op | ||
1126 | * Must check if file sparse. If not sparse, and not extending | ||
1127 | * then no need to do anything since file already allocated | ||
1128 | */ | ||
1129 | if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0) { | ||
1130 | if (keep_size == true) | ||
1131 | return 0; | ||
1132 | /* check if extending file */ | ||
1133 | else if (i_size_read(inode) >= off + len) | ||
1134 | /* not extending file and already not sparse */ | ||
1135 | return 0; | ||
1136 | /* BB: in future add else clause to extend file */ | ||
1137 | else | ||
1138 | return -EOPNOTSUPP; | ||
1139 | } | ||
1140 | |||
1141 | if ((keep_size == true) || (i_size_read(inode) >= off + len)) { | ||
1142 | /* | ||
1143 | * Check if falloc starts within first few pages of file | ||
1144 | * and ends within a few pages of the end of file to | ||
1145 | * ensure that most of file is being forced to be | ||
1146 | * fallocated now. If so then setting whole file sparse | ||
1147 | * ie potentially making a few extra pages at the beginning | ||
1148 | * or end of the file non-sparse via set_sparse is harmless. | ||
1149 | */ | ||
1150 | if ((off > 8192) || (off + len + 8192 < i_size_read(inode))) | ||
1151 | return -EOPNOTSUPP; | ||
1152 | |||
1153 | rc = smb2_set_sparse(xid, tcon, cfile, inode, false); | ||
1154 | } | ||
1155 | /* BB: else ... in future add code to extend file and set sparse */ | ||
1156 | |||
1157 | |||
1158 | free_xid(xid); | ||
1159 | return rc; | ||
1160 | } | ||
1161 | |||
1162 | |||
1105 | static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode, | 1163 | static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode, |
1106 | loff_t off, loff_t len) | 1164 | loff_t off, loff_t len) |
1107 | { | 1165 | { |
@@ -1112,7 +1170,10 @@ static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode, | |||
1112 | if (mode & FALLOC_FL_KEEP_SIZE) | 1170 | if (mode & FALLOC_FL_KEEP_SIZE) |
1113 | return smb3_zero_range(file, tcon, off, len, true); | 1171 | return smb3_zero_range(file, tcon, off, len, true); |
1114 | return smb3_zero_range(file, tcon, off, len, false); | 1172 | return smb3_zero_range(file, tcon, off, len, false); |
1115 | } | 1173 | } else if (mode == FALLOC_FL_KEEP_SIZE) |
1174 | return smb3_simple_falloc(file, tcon, off, len, true); | ||
1175 | else if (mode == 0) | ||
1176 | return smb3_simple_falloc(file, tcon, off, len, false); | ||
1116 | 1177 | ||
1117 | return -EOPNOTSUPP; | 1178 | return -EOPNOTSUPP; |
1118 | } | 1179 | } |