diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 88 |
1 files changed, 53 insertions, 35 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index f3f783dc4f75..72a5d5b04494 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/namei.h> | 14 | #include <linux/namei.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | 16 | ||
17 | static bool fuse_use_readdirplus(struct inode *dir, struct file *filp) | 17 | static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx) |
18 | { | 18 | { |
19 | struct fuse_conn *fc = get_fuse_conn(dir); | 19 | struct fuse_conn *fc = get_fuse_conn(dir); |
20 | struct fuse_inode *fi = get_fuse_inode(dir); | 20 | struct fuse_inode *fi = get_fuse_inode(dir); |
@@ -25,7 +25,7 @@ static bool fuse_use_readdirplus(struct inode *dir, struct file *filp) | |||
25 | return true; | 25 | return true; |
26 | if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state)) | 26 | if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state)) |
27 | return true; | 27 | return true; |
28 | if (filp->f_pos == 0) | 28 | if (ctx->pos == 0) |
29 | return true; | 29 | return true; |
30 | return false; | 30 | return false; |
31 | } | 31 | } |
@@ -1165,25 +1165,23 @@ static int fuse_permission(struct inode *inode, int mask) | |||
1165 | } | 1165 | } |
1166 | 1166 | ||
1167 | static int parse_dirfile(char *buf, size_t nbytes, struct file *file, | 1167 | static int parse_dirfile(char *buf, size_t nbytes, struct file *file, |
1168 | void *dstbuf, filldir_t filldir) | 1168 | struct dir_context *ctx) |
1169 | { | 1169 | { |
1170 | while (nbytes >= FUSE_NAME_OFFSET) { | 1170 | while (nbytes >= FUSE_NAME_OFFSET) { |
1171 | struct fuse_dirent *dirent = (struct fuse_dirent *) buf; | 1171 | struct fuse_dirent *dirent = (struct fuse_dirent *) buf; |
1172 | size_t reclen = FUSE_DIRENT_SIZE(dirent); | 1172 | size_t reclen = FUSE_DIRENT_SIZE(dirent); |
1173 | int over; | ||
1174 | if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) | 1173 | if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) |
1175 | return -EIO; | 1174 | return -EIO; |
1176 | if (reclen > nbytes) | 1175 | if (reclen > nbytes) |
1177 | break; | 1176 | break; |
1178 | 1177 | ||
1179 | over = filldir(dstbuf, dirent->name, dirent->namelen, | 1178 | if (!dir_emit(ctx, dirent->name, dirent->namelen, |
1180 | file->f_pos, dirent->ino, dirent->type); | 1179 | dirent->ino, dirent->type)) |
1181 | if (over) | ||
1182 | break; | 1180 | break; |
1183 | 1181 | ||
1184 | buf += reclen; | 1182 | buf += reclen; |
1185 | nbytes -= reclen; | 1183 | nbytes -= reclen; |
1186 | file->f_pos = dirent->off; | 1184 | ctx->pos = dirent->off; |
1187 | } | 1185 | } |
1188 | 1186 | ||
1189 | return 0; | 1187 | return 0; |
@@ -1225,30 +1223,46 @@ static int fuse_direntplus_link(struct file *file, | |||
1225 | if (name.name[1] == '.' && name.len == 2) | 1223 | if (name.name[1] == '.' && name.len == 2) |
1226 | return 0; | 1224 | return 0; |
1227 | } | 1225 | } |
1226 | |||
1227 | if (invalid_nodeid(o->nodeid)) | ||
1228 | return -EIO; | ||
1229 | if (!fuse_valid_type(o->attr.mode)) | ||
1230 | return -EIO; | ||
1231 | |||
1228 | fc = get_fuse_conn(dir); | 1232 | fc = get_fuse_conn(dir); |
1229 | 1233 | ||
1230 | name.hash = full_name_hash(name.name, name.len); | 1234 | name.hash = full_name_hash(name.name, name.len); |
1231 | dentry = d_lookup(parent, &name); | 1235 | dentry = d_lookup(parent, &name); |
1232 | if (dentry && dentry->d_inode) { | 1236 | if (dentry) { |
1233 | inode = dentry->d_inode; | 1237 | inode = dentry->d_inode; |
1234 | if (get_node_id(inode) == o->nodeid) { | 1238 | if (!inode) { |
1239 | d_drop(dentry); | ||
1240 | } else if (get_node_id(inode) != o->nodeid || | ||
1241 | ((o->attr.mode ^ inode->i_mode) & S_IFMT)) { | ||
1242 | err = d_invalidate(dentry); | ||
1243 | if (err) | ||
1244 | goto out; | ||
1245 | } else if (is_bad_inode(inode)) { | ||
1246 | err = -EIO; | ||
1247 | goto out; | ||
1248 | } else { | ||
1235 | struct fuse_inode *fi; | 1249 | struct fuse_inode *fi; |
1236 | fi = get_fuse_inode(inode); | 1250 | fi = get_fuse_inode(inode); |
1237 | spin_lock(&fc->lock); | 1251 | spin_lock(&fc->lock); |
1238 | fi->nlookup++; | 1252 | fi->nlookup++; |
1239 | spin_unlock(&fc->lock); | 1253 | spin_unlock(&fc->lock); |
1240 | 1254 | ||
1255 | fuse_change_attributes(inode, &o->attr, | ||
1256 | entry_attr_timeout(o), | ||
1257 | attr_version); | ||
1258 | |||
1241 | /* | 1259 | /* |
1242 | * The other branch to 'found' comes via fuse_iget() | 1260 | * The other branch to 'found' comes via fuse_iget() |
1243 | * which bumps nlookup inside | 1261 | * which bumps nlookup inside |
1244 | */ | 1262 | */ |
1245 | goto found; | 1263 | goto found; |
1246 | } | 1264 | } |
1247 | err = d_invalidate(dentry); | ||
1248 | if (err) | ||
1249 | goto out; | ||
1250 | dput(dentry); | 1265 | dput(dentry); |
1251 | dentry = NULL; | ||
1252 | } | 1266 | } |
1253 | 1267 | ||
1254 | dentry = d_alloc(parent, &name); | 1268 | dentry = d_alloc(parent, &name); |
@@ -1261,30 +1275,35 @@ static int fuse_direntplus_link(struct file *file, | |||
1261 | if (!inode) | 1275 | if (!inode) |
1262 | goto out; | 1276 | goto out; |
1263 | 1277 | ||
1264 | alias = d_materialise_unique(dentry, inode); | 1278 | if (S_ISDIR(inode->i_mode)) { |
1265 | err = PTR_ERR(alias); | 1279 | mutex_lock(&fc->inst_mutex); |
1266 | if (IS_ERR(alias)) | 1280 | alias = fuse_d_add_directory(dentry, inode); |
1267 | goto out; | 1281 | mutex_unlock(&fc->inst_mutex); |
1282 | err = PTR_ERR(alias); | ||
1283 | if (IS_ERR(alias)) { | ||
1284 | iput(inode); | ||
1285 | goto out; | ||
1286 | } | ||
1287 | } else { | ||
1288 | alias = d_splice_alias(inode, dentry); | ||
1289 | } | ||
1290 | |||
1268 | if (alias) { | 1291 | if (alias) { |
1269 | dput(dentry); | 1292 | dput(dentry); |
1270 | dentry = alias; | 1293 | dentry = alias; |
1271 | } | 1294 | } |
1272 | 1295 | ||
1273 | found: | 1296 | found: |
1274 | fuse_change_attributes(inode, &o->attr, entry_attr_timeout(o), | ||
1275 | attr_version); | ||
1276 | |||
1277 | fuse_change_entry_timeout(dentry, o); | 1297 | fuse_change_entry_timeout(dentry, o); |
1278 | 1298 | ||
1279 | err = 0; | 1299 | err = 0; |
1280 | out: | 1300 | out: |
1281 | if (dentry) | 1301 | dput(dentry); |
1282 | dput(dentry); | ||
1283 | return err; | 1302 | return err; |
1284 | } | 1303 | } |
1285 | 1304 | ||
1286 | static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, | 1305 | static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, |
1287 | void *dstbuf, filldir_t filldir, u64 attr_version) | 1306 | struct dir_context *ctx, u64 attr_version) |
1288 | { | 1307 | { |
1289 | struct fuse_direntplus *direntplus; | 1308 | struct fuse_direntplus *direntplus; |
1290 | struct fuse_dirent *dirent; | 1309 | struct fuse_dirent *dirent; |
@@ -1309,10 +1328,9 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, | |||
1309 | we need to send a FORGET for each of those | 1328 | we need to send a FORGET for each of those |
1310 | which we did not link. | 1329 | which we did not link. |
1311 | */ | 1330 | */ |
1312 | over = filldir(dstbuf, dirent->name, dirent->namelen, | 1331 | over = !dir_emit(ctx, dirent->name, dirent->namelen, |
1313 | file->f_pos, dirent->ino, | 1332 | dirent->ino, dirent->type); |
1314 | dirent->type); | 1333 | ctx->pos = dirent->off; |
1315 | file->f_pos = dirent->off; | ||
1316 | } | 1334 | } |
1317 | 1335 | ||
1318 | buf += reclen; | 1336 | buf += reclen; |
@@ -1326,7 +1344,7 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, | |||
1326 | return 0; | 1344 | return 0; |
1327 | } | 1345 | } |
1328 | 1346 | ||
1329 | static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | 1347 | static int fuse_readdir(struct file *file, struct dir_context *ctx) |
1330 | { | 1348 | { |
1331 | int plus, err; | 1349 | int plus, err; |
1332 | size_t nbytes; | 1350 | size_t nbytes; |
@@ -1349,17 +1367,17 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | |||
1349 | return -ENOMEM; | 1367 | return -ENOMEM; |
1350 | } | 1368 | } |
1351 | 1369 | ||
1352 | plus = fuse_use_readdirplus(inode, file); | 1370 | plus = fuse_use_readdirplus(inode, ctx); |
1353 | req->out.argpages = 1; | 1371 | req->out.argpages = 1; |
1354 | req->num_pages = 1; | 1372 | req->num_pages = 1; |
1355 | req->pages[0] = page; | 1373 | req->pages[0] = page; |
1356 | req->page_descs[0].length = PAGE_SIZE; | 1374 | req->page_descs[0].length = PAGE_SIZE; |
1357 | if (plus) { | 1375 | if (plus) { |
1358 | attr_version = fuse_get_attr_version(fc); | 1376 | attr_version = fuse_get_attr_version(fc); |
1359 | fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, | 1377 | fuse_read_fill(req, file, ctx->pos, PAGE_SIZE, |
1360 | FUSE_READDIRPLUS); | 1378 | FUSE_READDIRPLUS); |
1361 | } else { | 1379 | } else { |
1362 | fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, | 1380 | fuse_read_fill(req, file, ctx->pos, PAGE_SIZE, |
1363 | FUSE_READDIR); | 1381 | FUSE_READDIR); |
1364 | } | 1382 | } |
1365 | fuse_request_send(fc, req); | 1383 | fuse_request_send(fc, req); |
@@ -1369,11 +1387,11 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | |||
1369 | if (!err) { | 1387 | if (!err) { |
1370 | if (plus) { | 1388 | if (plus) { |
1371 | err = parse_dirplusfile(page_address(page), nbytes, | 1389 | err = parse_dirplusfile(page_address(page), nbytes, |
1372 | file, dstbuf, filldir, | 1390 | file, ctx, |
1373 | attr_version); | 1391 | attr_version); |
1374 | } else { | 1392 | } else { |
1375 | err = parse_dirfile(page_address(page), nbytes, file, | 1393 | err = parse_dirfile(page_address(page), nbytes, file, |
1376 | dstbuf, filldir); | 1394 | ctx); |
1377 | } | 1395 | } |
1378 | } | 1396 | } |
1379 | 1397 | ||
@@ -1886,7 +1904,7 @@ static const struct inode_operations fuse_dir_inode_operations = { | |||
1886 | static const struct file_operations fuse_dir_operations = { | 1904 | static const struct file_operations fuse_dir_operations = { |
1887 | .llseek = generic_file_llseek, | 1905 | .llseek = generic_file_llseek, |
1888 | .read = generic_read_dir, | 1906 | .read = generic_read_dir, |
1889 | .readdir = fuse_readdir, | 1907 | .iterate = fuse_readdir, |
1890 | .open = fuse_dir_open, | 1908 | .open = fuse_dir_open, |
1891 | .release = fuse_dir_release, | 1909 | .release = fuse_dir_release, |
1892 | .fsync = fuse_dir_fsync, | 1910 | .fsync = fuse_dir_fsync, |