Skip to content

Commit eae9e78

Browse files
dhowellsbrauner
authored andcommitted
afs: Use netfslib for symlinks, allowing them to be cached
Use netfslib to read symlinks, thereby allowing them to be cached by fscache and cachefiles. Signed-off-by: David Howells <[email protected]> Link: https://lore.kernel.org/r/[email protected] cc: Marc Dionne <[email protected]> cc: Jeff Layton <[email protected]> cc: [email protected] cc: [email protected] cc: [email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 6dd8093 commit eae9e78

File tree

5 files changed

+74
-49
lines changed

5 files changed

+74
-49
lines changed

fs/afs/file.c

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include "internal.h"
2121

2222
static int afs_file_mmap(struct file *file, struct vm_area_struct *vma);
23-
static int afs_symlink_read_folio(struct file *file, struct folio *folio);
2423

2524
static ssize_t afs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter);
2625
static ssize_t afs_file_splice_read(struct file *in, loff_t *ppos,
@@ -61,13 +60,6 @@ const struct address_space_operations afs_file_aops = {
6160
.writepages = afs_writepages,
6261
};
6362

64-
const struct address_space_operations afs_symlink_aops = {
65-
.read_folio = afs_symlink_read_folio,
66-
.release_folio = netfs_release_folio,
67-
.invalidate_folio = netfs_invalidate_folio,
68-
.migrate_folio = filemap_migrate_folio,
69-
};
70-
7163
static const struct vm_operations_struct afs_vm_ops = {
7264
.open = afs_vm_open,
7365
.close = afs_vm_close,
@@ -346,30 +338,6 @@ static void afs_issue_read(struct netfs_io_subrequest *subreq)
346338
queue_work(system_long_wq, &subreq->work);
347339
}
348340

349-
static int afs_symlink_read_folio(struct file *file, struct folio *folio)
350-
{
351-
struct afs_vnode *vnode = AFS_FS_I(folio->mapping->host);
352-
struct afs_read *fsreq;
353-
int ret;
354-
355-
fsreq = afs_alloc_read(GFP_NOFS);
356-
if (!fsreq)
357-
return -ENOMEM;
358-
359-
fsreq->pos = folio_pos(folio);
360-
fsreq->len = folio_size(folio);
361-
fsreq->vnode = vnode;
362-
fsreq->iter = &fsreq->def_iter;
363-
iov_iter_xarray(&fsreq->def_iter, ITER_DEST, &folio->mapping->i_pages,
364-
fsreq->pos, fsreq->len);
365-
366-
ret = afs_fetch_data(fsreq->vnode, fsreq);
367-
if (ret == 0)
368-
folio_mark_uptodate(folio);
369-
folio_unlock(folio);
370-
return ret;
371-
}
372-
373341
static int afs_init_request(struct netfs_io_request *rreq, struct file *file)
374342
{
375343
struct afs_vnode *vnode = AFS_FS_I(rreq->inode);

fs/afs/inode.c

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,60 @@
2525
#include "internal.h"
2626
#include "afs_fs.h"
2727

28+
static void afs_put_link(void *arg)
29+
{
30+
struct folio *folio = virt_to_folio(arg);
31+
32+
kunmap_local(arg);
33+
folio_put(folio);
34+
}
35+
36+
const char *afs_get_link(struct dentry *dentry, struct inode *inode,
37+
struct delayed_call *callback)
38+
{
39+
struct afs_vnode *vnode = AFS_FS_I(inode);
40+
struct folio *folio;
41+
char *content;
42+
ssize_t ret;
43+
44+
if (atomic64_read(&vnode->cb_expires_at) == AFS_NO_CB_PROMISE ||
45+
!test_bit(AFS_VNODE_DIR_READ, &vnode->flags)) {
46+
if (!dentry)
47+
return ERR_PTR(-ECHILD);
48+
ret = afs_read_single(vnode, NULL);
49+
if (ret < 0)
50+
return ERR_PTR(ret);
51+
}
52+
53+
folio = folioq_folio(vnode->directory, 0);
54+
folio_get(folio);
55+
content = kmap_local_folio(folio, 0);
56+
set_delayed_call(callback, afs_put_link, content);
57+
return content;
58+
}
59+
60+
int afs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
61+
{
62+
DEFINE_DELAYED_CALL(done);
63+
const char *content;
64+
int len;
65+
66+
content = afs_get_link(dentry, d_inode(dentry), &done);
67+
if (IS_ERR(content)) {
68+
do_delayed_call(&done);
69+
return PTR_ERR(content);
70+
}
71+
72+
len = umin(strlen(content), buflen);
73+
if (copy_to_user(buffer, content, len))
74+
len = -EFAULT;
75+
do_delayed_call(&done);
76+
return len;
77+
}
78+
2879
static const struct inode_operations afs_symlink_inode_operations = {
29-
.get_link = page_get_link,
80+
.get_link = afs_get_link,
81+
.readlink = afs_readlink,
3082
};
3183

3284
static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *parent_vnode)
@@ -124,13 +176,13 @@ static int afs_inode_init_from_status(struct afs_operation *op,
124176
inode->i_mode = S_IFDIR | 0555;
125177
inode->i_op = &afs_mntpt_inode_operations;
126178
inode->i_fop = &afs_mntpt_file_operations;
127-
inode->i_mapping->a_ops = &afs_symlink_aops;
128179
} else {
129180
inode->i_mode = S_IFLNK | status->mode;
130181
inode->i_op = &afs_symlink_inode_operations;
131-
inode->i_mapping->a_ops = &afs_symlink_aops;
132182
}
183+
inode->i_mapping->a_ops = &afs_dir_aops;
133184
inode_nohighmem(inode);
185+
mapping_set_release_always(inode->i_mapping);
134186
break;
135187
default:
136188
dump_vnode(vnode, op->file[0].vnode != vnode ? op->file[0].vnode : NULL);
@@ -443,7 +495,8 @@ static void afs_get_inode_cache(struct afs_vnode *vnode)
443495
struct afs_vnode_cache_aux aux;
444496

445497
if (vnode->status.type != AFS_FTYPE_FILE &&
446-
vnode->status.type != AFS_FTYPE_DIR) {
498+
vnode->status.type != AFS_FTYPE_DIR &&
499+
vnode->status.type != AFS_FTYPE_SYMLINK) {
447500
vnode->netfs.cache = NULL;
448501
return;
449502
}
@@ -657,7 +710,8 @@ void afs_evict_inode(struct inode *inode)
657710

658711
ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);
659712

660-
if ((S_ISDIR(inode->i_mode)) &&
713+
if ((S_ISDIR(inode->i_mode) ||
714+
S_ISLNK(inode->i_mode)) &&
661715
(inode->i_state & I_DIRTY) &&
662716
!sbi->dyn_root) {
663717
struct writeback_control wbc = {

fs/afs/internal.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,6 @@ extern void afs_dynroot_depopulate(struct super_block *);
11161116
* file.c
11171117
*/
11181118
extern const struct address_space_operations afs_file_aops;
1119-
extern const struct address_space_operations afs_symlink_aops;
11201119
extern const struct inode_operations afs_file_inode_operations;
11211120
extern const struct file_operations afs_file_operations;
11221121
extern const struct netfs_request_ops afs_req_ops;
@@ -1222,6 +1221,9 @@ extern void afs_fs_probe_cleanup(struct afs_net *);
12221221
*/
12231222
extern const struct afs_operation_ops afs_fetch_status_operation;
12241223

1224+
const char *afs_get_link(struct dentry *dentry, struct inode *inode,
1225+
struct delayed_call *callback);
1226+
int afs_readlink(struct dentry *dentry, char __user *buffer, int buflen);
12251227
extern void afs_vnode_commit_status(struct afs_operation *, struct afs_vnode_param *);
12261228
extern int afs_fetch_status(struct afs_vnode *, struct key *, bool, afs_access_t *);
12271229
extern int afs_ilookup5_test_by_fid(struct inode *, void *);

fs/afs/mntpt.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const struct file_operations afs_mntpt_file_operations = {
3030

3131
const struct inode_operations afs_mntpt_inode_operations = {
3232
.lookup = afs_mntpt_lookup,
33-
.readlink = page_readlink,
33+
.readlink = afs_readlink,
3434
.getattr = afs_getattr,
3535
};
3636

@@ -118,26 +118,26 @@ static int afs_mntpt_set_params(struct fs_context *fc, struct dentry *mntpt)
118118
ctx->volnamesz = sizeof(afs_root_volume) - 1;
119119
} else {
120120
/* read the contents of the AFS special symlink */
121-
struct page *page;
121+
DEFINE_DELAYED_CALL(cleanup);
122+
const char *content;
122123
loff_t size = i_size_read(d_inode(mntpt));
123-
char *buf;
124124

125125
if (src_as->cell)
126126
ctx->cell = afs_use_cell(src_as->cell, afs_cell_trace_use_mntpt);
127127

128128
if (size < 2 || size > PAGE_SIZE - 1)
129129
return -EINVAL;
130130

131-
page = read_mapping_page(d_inode(mntpt)->i_mapping, 0, NULL);
132-
if (IS_ERR(page))
133-
return PTR_ERR(page);
131+
content = afs_get_link(mntpt, d_inode(mntpt), &cleanup);
132+
if (IS_ERR(content)) {
133+
do_delayed_call(&cleanup);
134+
return PTR_ERR(content);
135+
}
134136

135-
buf = kmap(page);
136137
ret = -EINVAL;
137-
if (buf[size - 1] == '.')
138-
ret = vfs_parse_fs_string(fc, "source", buf, size - 1);
139-
kunmap(page);
140-
put_page(page);
138+
if (content[size - 1] == '.')
139+
ret = vfs_parse_fs_string(fc, "source", content, size - 1);
140+
do_delayed_call(&cleanup);
141141
if (ret < 0)
142142
return ret;
143143

include/trace/events/afs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ enum yfs_cm_operation {
422422
EM(afs_file_error_dir_over_end, "DIR_ENT_OVER_END") \
423423
EM(afs_file_error_dir_small, "DIR_SMALL") \
424424
EM(afs_file_error_dir_unmarked_ext, "DIR_UNMARKED_EXT") \
425+
EM(afs_file_error_symlink_big, "SYM_BIG") \
425426
EM(afs_file_error_mntpt, "MNTPT_READ_FAILED") \
426427
E_(afs_file_error_writeback_fail, "WRITEBACK_FAILED")
427428

0 commit comments

Comments
 (0)