aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r--fs/fuse/dir.c88
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
17static bool fuse_use_readdirplus(struct inode *dir, struct file *filp) 17static 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
1167static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 1167static 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
1273found: 1296found:
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;
1280out: 1300out:
1281 if (dentry) 1301 dput(dentry);
1282 dput(dentry);
1283 return err; 1302 return err;
1284} 1303}
1285 1304
1286static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, 1305static 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
1329static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) 1347static 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 = {
1886static const struct file_operations fuse_dir_operations = { 1904static 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,