Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
ef818a2
Documentation
arch
block
crypto
drivers
fs
9p
adfs
affs
afs
autofs
autofs4
befs
bfs
cifs
coda
configfs
cramfs
debugfs
devpts
dlm
ecryptfs
efs
exportfs
ext2
ext3
ext4
fat
freevxfs
fuse
gfs2
hfs
hfsplus
hostfs
hpfs
hppfs
hugetlbfs
isofs
jbd
jbd2
jffs2
jfs
lockd
minix
msdos
ncpfs
nfs
Makefile
callback.c
callback.h
callback_proc.c
callback_xdr.c
client.c
delegation.c
delegation.h
dir.c
direct.c
file.c
getroot.c
idmap.c
inode.c
internal.h
iostat.h
mount_clnt.c
namespace.c
nfs2xdr.c
nfs3acl.c
nfs3proc.c
nfs3xdr.c
nfs4_fs.h
nfs4namespace.c
nfs4proc.c
nfs4renewd.c
nfs4state.c
nfs4xdr.c
nfsroot.c
pagelist.c
proc.c
read.c
super.c
symlink.c
sysctl.c
unlink.c
write.c
nfs_common
nfsd
nls
ntfs
ocfs2
openpromfs
partitions
proc
qnx4
ramfs
reiserfs
romfs
smbfs
sysfs
sysv
udf
ufs
vfat
xfs
Kconfig
Kconfig.binfmt
Makefile
aio.c
anon_inodes.c
attr.c
bad_inode.c
binfmt_aout.c
binfmt_elf.c
binfmt_elf_fdpic.c
binfmt_em86.c
binfmt_flat.c
binfmt_misc.c
binfmt_script.c
binfmt_som.c
bio.c
block_dev.c
buffer.c
char_dev.c
compat.c
compat_ioctl.c
dcache.c
dcookies.c
direct-io.c
dnotify.c
dquot.c
drop_caches.c
eventfd.c
eventpoll.c
exec.c
fcntl.c
fifo.c
file.c
file_table.c
filesystems.c
fs-writeback.c
generic_acl.c
inode.c
inotify.c
inotify_user.c
internal.h
ioctl.c
ioprio.c
libfs.c
locks.c
mbcache.c
mpage.c
namei.c
namespace.c
nfsctl.c
no-block.c
open.c
pipe.c
pnode.c
pnode.h
posix_acl.c
quota.c
quota_v1.c
quota_v2.c
read_write.c
read_write.h
readdir.c
select.c
seq_file.c
signalfd.c
splice.c
stack.c
stat.c
super.c
sync.c
timerfd.c
utimes.c
xattr.c
xattr_acl.c
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
usr
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
fs
/
nfs
/
unlink.c
Copy path
Blame
Blame
Latest commit
History
History
288 lines (255 loc) · 6.69 KB
Breadcrumbs
linux
/
fs
/
nfs
/
unlink.c
Top
File metadata and controls
Code
Blame
288 lines (255 loc) · 6.69 KB
Raw
/* * linux/fs/nfs/unlink.c * * nfs sillydelete handling * */ #include <linux/slab.h> #include <linux/string.h> #include <linux/dcache.h> #include <linux/sunrpc/sched.h> #include <linux/sunrpc/clnt.h> #include <linux/nfs_fs.h> #include <linux/sched.h> #include <linux/wait.h> #include "internal.h" struct nfs_unlinkdata { struct hlist_node list; struct nfs_removeargs args; struct nfs_removeres res; struct inode *dir; struct rpc_cred *cred; }; /** * nfs_free_unlinkdata - release data from a sillydelete operation. * @data: pointer to unlink structure. */ static void nfs_free_unlinkdata(struct nfs_unlinkdata *data) { iput(data->dir); put_rpccred(data->cred); kfree(data->args.name.name); kfree(data); } #define NAME_ALLOC_LEN(len) ((len+16) & ~15) /** * nfs_copy_dname - copy dentry name to data structure * @dentry: pointer to dentry * @data: nfs_unlinkdata */ static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data) { char *str; int len = dentry->d_name.len; str = kmemdup(dentry->d_name.name, NAME_ALLOC_LEN(len), GFP_KERNEL); if (!str) return -ENOMEM; data->args.name.len = len; data->args.name.name = str; return 0; } static void nfs_free_dname(struct nfs_unlinkdata *data) { kfree(data->args.name.name); data->args.name.name = NULL; data->args.name.len = 0; } static void nfs_dec_sillycount(struct inode *dir) { struct nfs_inode *nfsi = NFS_I(dir); if (atomic_dec_return(&nfsi->silly_count) == 1) wake_up(&nfsi->waitqueue); } /** * nfs_async_unlink_init - Initialize the RPC info * task: rpc_task of the sillydelete */ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) { struct nfs_unlinkdata *data = calldata; struct inode *dir = data->dir; struct rpc_message msg = { .rpc_argp = &data->args, .rpc_resp = &data->res, .rpc_cred = data->cred, }; NFS_PROTO(dir)->unlink_setup(&msg, dir); rpc_call_setup(task, &msg, 0); } /** * nfs_async_unlink_done - Sillydelete post-processing * @task: rpc_task of the sillydelete * * Do the directory attribute update. */ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) { struct nfs_unlinkdata *data = calldata; struct inode *dir = data->dir; if (!NFS_PROTO(dir)->unlink_done(task, dir)) rpc_restart_call(task); } /** * nfs_async_unlink_release - Release the sillydelete data. * @task: rpc_task of the sillydelete * * We need to call nfs_put_unlinkdata as a 'tk_release' task since the * rpc_task would be freed too. */ static void nfs_async_unlink_release(void *calldata) { struct nfs_unlinkdata *data = calldata; nfs_dec_sillycount(data->dir); nfs_sb_deactive(NFS_SERVER(data->dir)); nfs_free_unlinkdata(data); } static const struct rpc_call_ops nfs_unlink_ops = { .rpc_call_prepare = nfs_async_unlink_init, .rpc_call_done = nfs_async_unlink_done, .rpc_release = nfs_async_unlink_release, }; static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) { struct rpc_task *task; struct dentry *alias; alias = d_lookup(parent, &data->args.name); if (alias != NULL) { int ret = 0; /* * Hey, we raced with lookup... See if we need to transfer * the sillyrename information to the aliased dentry. */ nfs_free_dname(data); spin_lock(&alias->d_lock); if (alias->d_inode != NULL && !(alias->d_flags & DCACHE_NFSFS_RENAMED)) { alias->d_fsdata = data; alias->d_flags |= DCACHE_NFSFS_RENAMED; ret = 1; } spin_unlock(&alias->d_lock); nfs_dec_sillycount(dir); dput(alias); return ret; } data->dir = igrab(dir); if (!data->dir) { nfs_dec_sillycount(dir); return 0; } nfs_sb_active(NFS_SERVER(dir)); data->args.fh = NFS_FH(dir); nfs_fattr_init(&data->res.dir_attr); task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data); if (!IS_ERR(task)) rpc_put_task(task); return 1; } static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data) { struct dentry *parent; struct inode *dir; int ret = 0; parent = dget_parent(dentry); if (parent == NULL) goto out_free; dir = parent->d_inode; if (nfs_copy_dname(dentry, data) != 0) goto out_dput; /* Non-exclusive lock protects against concurrent lookup() calls */ spin_lock(&dir->i_lock); if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) == 0) { /* Deferred delete */ hlist_add_head(&data->list, &NFS_I(dir)->silly_list); spin_unlock(&dir->i_lock); ret = 1; goto out_dput; } spin_unlock(&dir->i_lock); ret = nfs_do_call_unlink(parent, dir, data); out_dput: dput(parent); out_free: return ret; } void nfs_block_sillyrename(struct dentry *dentry) { struct nfs_inode *nfsi = NFS_I(dentry->d_inode); wait_event(nfsi->waitqueue, atomic_cmpxchg(&nfsi->silly_count, 1, 0) == 1); } void nfs_unblock_sillyrename(struct dentry *dentry) { struct inode *dir = dentry->d_inode; struct nfs_inode *nfsi = NFS_I(dir); struct nfs_unlinkdata *data; atomic_inc(&nfsi->silly_count); spin_lock(&dir->i_lock); while (!hlist_empty(&nfsi->silly_list)) { if (!atomic_inc_not_zero(&nfsi->silly_count)) break; data = hlist_entry(nfsi->silly_list.first, struct nfs_unlinkdata, list); hlist_del(&data->list); spin_unlock(&dir->i_lock); if (nfs_do_call_unlink(dentry, dir, data) == 0) nfs_free_unlinkdata(data); spin_lock(&dir->i_lock); } spin_unlock(&dir->i_lock); } /** * nfs_async_unlink - asynchronous unlinking of a file * @dir: parent directory of dentry * @dentry: dentry to unlink */ int nfs_async_unlink(struct inode *dir, struct dentry *dentry) { struct nfs_unlinkdata *data; int status = -ENOMEM; data = kzalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) goto out; data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); if (IS_ERR(data->cred)) { status = PTR_ERR(data->cred); goto out_free; } status = -EBUSY; spin_lock(&dentry->d_lock); if (dentry->d_flags & DCACHE_NFSFS_RENAMED) goto out_unlock; dentry->d_flags |= DCACHE_NFSFS_RENAMED; dentry->d_fsdata = data; spin_unlock(&dentry->d_lock); return 0; out_unlock: spin_unlock(&dentry->d_lock); put_rpccred(data->cred); out_free: kfree(data); out: return status; } /** * nfs_complete_unlink - Initialize completion of the sillydelete * @dentry: dentry to delete * @inode: inode * * Since we're most likely to be called by dentry_iput(), we * only use the dentry to find the sillydelete. We then copy the name * into the qstr. */ void nfs_complete_unlink(struct dentry *dentry, struct inode *inode) { struct nfs_unlinkdata *data = NULL; spin_lock(&dentry->d_lock); if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; data = dentry->d_fsdata; } spin_unlock(&dentry->d_lock); if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data))) nfs_free_unlinkdata(data); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
You can’t perform that action at this time.