Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
119dcc73
Commit
119dcc73
authored
Nov 25, 2023
by
Al Viro
Browse files
Options
Browse Files
Download
Plain Diff
Merge branches 'work.dcache-misc' and 'work.dcache2' into work.dcache
parents
ef69f050
6367b491
Changes
13
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
296 additions
and
431 deletions
+296
-431
Documentation/filesystems/porting.rst
Documentation/filesystems/porting.rst
+34
-0
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/cell/spufs/inode.c
+3
-2
fs/afs/dynroot.c
fs/afs/dynroot.c
+3
-2
fs/autofs/expire.c
fs/autofs/expire.c
+2
-5
fs/ceph/dir.c
fs/ceph/dir.c
+1
-1
fs/ceph/mds_client.c
fs/ceph/mds_client.c
+1
-1
fs/coda/cache.c
fs/coda/cache.c
+4
-4
fs/dcache.c
fs/dcache.c
+183
-310
fs/libfs.c
fs/libfs.c
+21
-24
fs/nfsd/nfsctl.c
fs/nfsd/nfsctl.c
+14
-56
fs/notify/fsnotify.c
fs/notify/fsnotify.c
+1
-1
fs/tracefs/inode.c
fs/tracefs/inode.c
+14
-20
include/linux/dcache.h
include/linux/dcache.h
+15
-5
No files found.
Documentation/filesystems/porting.rst
View file @
119dcc73
...
...
@@ -1061,3 +1061,37 @@ export_operations ->encode_fh() no longer has a default implementation to
encode FILEID_INO32_GEN* file handles.
Filesystems that used the default implementation may use the generic helper
generic_encode_ino32_fh() explicitly.
---
**mandatory**
The list of children anchored in parent dentry got turned into hlist now.
Field names got changed (->d_children/->d_sib instead of ->d_subdirs/->d_child
for anchor/entries resp.), so any affected places will be immediately caught
by compiler.
---
**mandatory**
->d_delete() instances are now called for dentries with ->d_lock held
and refcount equal to 0. They are not permitted to drop/regain ->d_lock.
None of in-tree instances did anything of that sort. Make sure yours do not...
--
**mandatory**
->d_prune() instances are now called without ->d_lock held on the parent.
->d_lock on dentry itself is still held; if you need per-parent exclusions (none
of the in-tree instances did), use your own spinlock.
->d_iput() and ->d_release() are called with victim dentry still in the
list of parent's children. It is still unhashed, marked killed, etc., just not
removed from parent's ->d_children yet.
Anyone iterating through the list of children needs to be aware of the
half-killed dentries that might be seen there; taking ->d_lock on those will
see them negative, unhashed and with negative refcount, which means that most
of the in-kernel users would've done the right thing anyway without any adjustment.
arch/powerpc/platforms/cell/spufs/inode.c
View file @
119dcc73
...
...
@@ -145,10 +145,11 @@ spufs_evict_inode(struct inode *inode)
static
void
spufs_prune_dir
(
struct
dentry
*
dir
)
{
struct
dentry
*
dentry
,
*
tmp
;
struct
dentry
*
dentry
;
struct
hlist_node
*
n
;
inode_lock
(
d_inode
(
dir
));
list_for_each_entry_safe
(
dentry
,
tmp
,
&
dir
->
d_subdirs
,
d_child
)
{
hlist_for_each_entry_safe
(
dentry
,
n
,
&
dir
->
d_children
,
d_sib
)
{
spin_lock
(
&
dentry
->
d_lock
);
if
(
simple_positive
(
dentry
))
{
dget_dlock
(
dentry
);
...
...
fs/afs/dynroot.c
View file @
119dcc73
...
...
@@ -370,7 +370,7 @@ int afs_dynroot_populate(struct super_block *sb)
void
afs_dynroot_depopulate
(
struct
super_block
*
sb
)
{
struct
afs_net
*
net
=
afs_sb2net
(
sb
);
struct
dentry
*
root
=
sb
->
s_root
,
*
subdir
,
*
tmp
;
struct
dentry
*
root
=
sb
->
s_root
,
*
subdir
;
/* Prevent more subdirs from being created */
mutex_lock
(
&
net
->
proc_cells_lock
);
...
...
@@ -379,10 +379,11 @@ void afs_dynroot_depopulate(struct super_block *sb)
mutex_unlock
(
&
net
->
proc_cells_lock
);
if
(
root
)
{
struct
hlist_node
*
n
;
inode_lock
(
root
->
d_inode
);
/* Remove all the pins for dirs created for manually added cells */
list_for_each_entry_safe
(
subdir
,
tmp
,
&
root
->
d_subdirs
,
d_child
)
{
hlist_for_each_entry_safe
(
subdir
,
n
,
&
root
->
d_children
,
d_sib
)
{
if
(
subdir
->
d_fsdata
)
{
subdir
->
d_fsdata
=
NULL
;
dput
(
subdir
);
...
...
fs/autofs/expire.c
View file @
119dcc73
...
...
@@ -73,12 +73,9 @@ static int autofs_mount_busy(struct vfsmount *mnt,
/* p->d_lock held */
static
struct
dentry
*
positive_after
(
struct
dentry
*
p
,
struct
dentry
*
child
)
{
if
(
child
)
child
=
list_next_entry
(
child
,
d_child
);
else
child
=
list_first_entry
(
&
p
->
d_subdirs
,
struct
dentry
,
d_child
);
child
=
child
?
d_next_sibling
(
child
)
:
d_first_child
(
p
);
list_for_each_entry_from
(
child
,
&
p
->
d_subdirs
,
d_child
)
{
hlist_for_each_entry_from
(
child
,
d_sib
)
{
spin_lock_nested
(
&
child
->
d_lock
,
DENTRY_D_LOCK_NESTED
);
if
(
simple_positive
(
child
))
{
dget_dlock
(
child
);
...
...
fs/ceph/dir.c
View file @
119dcc73
...
...
@@ -174,7 +174,7 @@ __dcache_find_get_entry(struct dentry *parent, u64 idx,
/*
* When possible, we try to satisfy a readdir by peeking at the
* dcache. We make this work by carefully ordering dentries on
* d_child when we initially get results back from the MDS, and
* d_child
ren
when we initially get results back from the MDS, and
* falling back to a "normal" sync readdir if any dentries in the dir
* are dropped.
*
...
...
fs/ceph/mds_client.c
View file @
119dcc73
...
...
@@ -2128,7 +2128,7 @@ static bool drop_negative_children(struct dentry *dentry)
goto
out
;
spin_lock
(
&
dentry
->
d_lock
);
list_for_each_entry
(
child
,
&
dentry
->
d_subdirs
,
d_child
)
{
hlist_for_each_entry
(
child
,
&
dentry
->
d_children
,
d_sib
)
{
if
(
d_really_is_positive
(
child
))
{
all_negative
=
false
;
break
;
...
...
fs/coda/cache.c
View file @
119dcc73
...
...
@@ -93,13 +93,13 @@ static void coda_flag_children(struct dentry *parent, int flag)
struct
dentry
*
de
;
spin_lock
(
&
parent
->
d_lock
);
list_for_each_entry
(
de
,
&
parent
->
d_subdirs
,
d_child
)
{
hlist_for_each_entry
(
de
,
&
parent
->
d_children
,
d_sib
)
{
struct
inode
*
inode
=
d_inode_rcu
(
de
);
/* don't know what to do with negative dentries */
if
(
d_inode
(
de
)
)
coda_flag_inode
(
d_inode
(
de
)
,
flag
);
if
(
inode
)
coda_flag_inode
(
inode
,
flag
);
}
spin_unlock
(
&
parent
->
d_lock
);
return
;
}
void
coda_flag_inode_children
(
struct
inode
*
inode
,
int
flag
)
...
...
fs/dcache.c
View file @
119dcc73
This diff is collapsed.
Click to expand it.
fs/libfs.c
View file @
119dcc73
...
...
@@ -104,15 +104,16 @@ EXPORT_SYMBOL(dcache_dir_close);
* If no such element exists, NULL is returned.
*/
static
struct
dentry
*
scan_positives
(
struct
dentry
*
cursor
,
struct
list_head
*
p
,
struct
hlist_node
*
*
p
,
loff_t
count
,
struct
dentry
*
last
)
{
struct
dentry
*
dentry
=
cursor
->
d_parent
,
*
found
=
NULL
;
spin_lock
(
&
dentry
->
d_lock
);
while
((
p
=
p
->
next
)
!=
&
dentry
->
d_subdirs
)
{
struct
dentry
*
d
=
list_entry
(
p
,
struct
dentry
,
d_child
);
while
(
*
p
)
{
struct
dentry
*
d
=
hlist_entry
(
*
p
,
struct
dentry
,
d_sib
);
p
=
&
d
->
d_sib
.
next
;
// we must at least skip cursors, to avoid livelocks
if
(
d
->
d_flags
&
DCACHE_DENTRY_CURSOR
)
continue
;
...
...
@@ -126,8 +127,10 @@ static struct dentry *scan_positives(struct dentry *cursor,
count
=
1
;
}
if
(
need_resched
())
{
list_move
(
&
cursor
->
d_child
,
p
);
p
=
&
cursor
->
d_child
;
if
(
!
hlist_unhashed
(
&
cursor
->
d_sib
))
__hlist_del
(
&
cursor
->
d_sib
);
hlist_add_behind
(
&
cursor
->
d_sib
,
&
d
->
d_sib
);
p
=
&
cursor
->
d_sib
.
next
;
spin_unlock
(
&
dentry
->
d_lock
);
cond_resched
();
spin_lock
(
&
dentry
->
d_lock
);
...
...
@@ -159,13 +162,12 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
inode_lock_shared
(
dentry
->
d_inode
);
if
(
offset
>
2
)
to
=
scan_positives
(
cursor
,
&
dentry
->
d_
subdirs
,
to
=
scan_positives
(
cursor
,
&
dentry
->
d_
children
.
first
,
offset
-
2
,
NULL
);
spin_lock
(
&
dentry
->
d_lock
);
hlist_del_init
(
&
cursor
->
d_sib
);
if
(
to
)
list_move
(
&
cursor
->
d_child
,
&
to
->
d_child
);
else
list_del_init
(
&
cursor
->
d_child
);
hlist_add_behind
(
&
cursor
->
d_sib
,
&
to
->
d_sib
);
spin_unlock
(
&
dentry
->
d_lock
);
dput
(
to
);
...
...
@@ -187,19 +189,16 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
{
struct
dentry
*
dentry
=
file
->
f_path
.
dentry
;
struct
dentry
*
cursor
=
file
->
private_data
;
struct
list_head
*
anchor
=
&
dentry
->
d_subdirs
;
struct
dentry
*
next
=
NULL
;
struct
list_head
*
p
;
struct
hlist_node
*
*
p
;
if
(
!
dir_emit_dots
(
file
,
ctx
))
return
0
;
if
(
ctx
->
pos
==
2
)
p
=
anchor
;
else
if
(
!
list_empty
(
&
cursor
->
d_child
))
p
=
&
cursor
->
d_child
;
p
=
&
dentry
->
d_children
.
first
;
else
return
0
;
p
=
&
cursor
->
d_sib
.
next
;
while
((
next
=
scan_positives
(
cursor
,
p
,
1
,
next
))
!=
NULL
)
{
if
(
!
dir_emit
(
ctx
,
next
->
d_name
.
name
,
next
->
d_name
.
len
,
...
...
@@ -207,13 +206,12 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
fs_umode_to_dtype
(
d_inode
(
next
)
->
i_mode
)))
break
;
ctx
->
pos
++
;
p
=
&
next
->
d_
child
;
p
=
&
next
->
d_
sib
.
next
;
}
spin_lock
(
&
dentry
->
d_lock
);
hlist_del_init
(
&
cursor
->
d_sib
);
if
(
next
)
list_move_tail
(
&
cursor
->
d_child
,
&
next
->
d_child
);
else
list_del_init
(
&
cursor
->
d_child
);
hlist_add_before
(
&
cursor
->
d_sib
,
&
next
->
d_sib
);
spin_unlock
(
&
dentry
->
d_lock
);
dput
(
next
);
...
...
@@ -492,12 +490,11 @@ const struct file_operations simple_offset_dir_operations = {
static
struct
dentry
*
find_next_child
(
struct
dentry
*
parent
,
struct
dentry
*
prev
)
{
struct
dentry
*
child
=
NULL
;
struct
list_head
*
p
=
prev
?
&
prev
->
d_child
:
&
parent
->
d_subdirs
;
struct
dentry
*
child
=
NULL
,
*
d
;
spin_lock
(
&
parent
->
d_lock
);
while
((
p
=
p
->
next
)
!=
&
parent
->
d_subdirs
)
{
struct
dentry
*
d
=
container_of
(
p
,
struct
dentry
,
d_child
);
d
=
prev
?
d_next_sibling
(
prev
)
:
d_first_child
(
parent
);
hlist_for_each_entry_from
(
d
,
d_sib
)
{
if
(
simple_positive
(
d
))
{
spin_lock_nested
(
&
d
->
d_lock
,
DENTRY_D_LOCK_NESTED
);
if
(
simple_positive
(
d
))
...
...
@@ -658,7 +655,7 @@ int simple_empty(struct dentry *dentry)
int
ret
=
0
;
spin_lock
(
&
dentry
->
d_lock
);
list_for_each_entry
(
child
,
&
dentry
->
d_subdirs
,
d_child
)
{
hlist_for_each_entry
(
child
,
&
dentry
->
d_children
,
d_sib
)
{
spin_lock_nested
(
&
child
->
d_lock
,
DENTRY_D_LOCK_NESTED
);
if
(
simple_positive
(
child
))
{
spin_unlock
(
&
child
->
d_lock
);
...
...
fs/nfsd/nfsctl.c
View file @
119dcc73
...
...
@@ -1236,63 +1236,34 @@ static inline void _nfsd_symlink(struct dentry *parent, const char *name,
#endif
static
void
clear_ncl
(
struct
inode
*
inode
)
static
void
clear_ncl
(
struct
dentry
*
dentry
)
{
struct
inode
*
inode
=
d_inode
(
dentry
);
struct
nfsdfs_client
*
ncl
=
inode
->
i_private
;
spin_lock
(
&
inode
->
i_lock
);
inode
->
i_private
=
NULL
;
spin_unlock
(
&
inode
->
i_lock
);
kref_put
(
&
ncl
->
cl_ref
,
ncl
->
cl_release
);
}
static
struct
nfsdfs_client
*
__get_nfsdfs_client
(
struct
inode
*
inode
)
{
struct
nfsdfs_client
*
nc
=
inode
->
i_private
;
if
(
nc
)
kref_get
(
&
nc
->
cl_ref
);
return
nc
;
}
struct
nfsdfs_client
*
get_nfsdfs_client
(
struct
inode
*
inode
)
{
struct
nfsdfs_client
*
nc
;
inode_lock_shared
(
inode
);
nc
=
__get_nfsdfs_client
(
inode
);
inode_unlock_shared
(
inode
);
spin_lock
(
&
inode
->
i_lock
);
nc
=
inode
->
i_private
;
if
(
nc
)
kref_get
(
&
nc
->
cl_ref
);
spin_unlock
(
&
inode
->
i_lock
);
return
nc
;
}
/* from __rpc_unlink */
static
void
nfsdfs_remove_file
(
struct
inode
*
dir
,
struct
dentry
*
dentry
)
{
int
ret
;
clear_ncl
(
d_inode
(
dentry
));
dget
(
dentry
);
ret
=
simple_unlink
(
dir
,
dentry
);
d_drop
(
dentry
);
fsnotify_unlink
(
dir
,
dentry
);
dput
(
dentry
);
WARN_ON_ONCE
(
ret
);
}
static
void
nfsdfs_remove_files
(
struct
dentry
*
root
)
{
struct
dentry
*
dentry
,
*
tmp
;
list_for_each_entry_safe
(
dentry
,
tmp
,
&
root
->
d_subdirs
,
d_child
)
{
if
(
!
simple_positive
(
dentry
))
{
WARN_ON_ONCE
(
1
);
/* I think this can't happen? */
continue
;
}
nfsdfs_remove_file
(
d_inode
(
root
),
dentry
);
}
}
/* XXX: cut'n'paste from simple_fill_super; figure out if we could share
* code instead. */
static
int
nfsdfs_create_files
(
struct
dentry
*
root
,
const
struct
tree_descr
*
files
,
struct
nfsdfs_client
*
ncl
,
struct
dentry
**
fdentries
)
{
struct
inode
*
dir
=
d_inode
(
root
);
...
...
@@ -1311,8 +1282,9 @@ static int nfsdfs_create_files(struct dentry *root,
dput
(
dentry
);
goto
out
;
}
kref_get
(
&
ncl
->
cl_ref
);
inode
->
i_fop
=
files
->
ops
;
inode
->
i_private
=
__get_nfsdfs_client
(
dir
)
;
inode
->
i_private
=
ncl
;
d_add
(
dentry
,
inode
);
fsnotify_create
(
dir
,
dentry
);
if
(
fdentries
)
...
...
@@ -1321,7 +1293,6 @@ static int nfsdfs_create_files(struct dentry *root,
inode_unlock
(
dir
);
return
0
;
out:
nfsdfs_remove_files
(
root
);
inode_unlock
(
dir
);
return
-
ENOMEM
;
}
...
...
@@ -1341,7 +1312,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
dentry
=
nfsd_mkdir
(
nn
->
nfsd_client_dir
,
ncl
,
name
);
if
(
IS_ERR
(
dentry
))
/* XXX: tossing errors? */
return
NULL
;
ret
=
nfsdfs_create_files
(
dentry
,
files
,
fdentries
);
ret
=
nfsdfs_create_files
(
dentry
,
files
,
ncl
,
fdentries
);
if
(
ret
)
{
nfsd_client_rmdir
(
dentry
);
return
NULL
;
...
...
@@ -1352,20 +1323,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
/* Taken from __rpc_rmdir: */
void
nfsd_client_rmdir
(
struct
dentry
*
dentry
)
{
struct
inode
*
dir
=
d_inode
(
dentry
->
d_parent
);
struct
inode
*
inode
=
d_inode
(
dentry
);
int
ret
;
inode_lock
(
dir
);
nfsdfs_remove_files
(
dentry
);
clear_ncl
(
inode
);
dget
(
dentry
);
ret
=
simple_rmdir
(
dir
,
dentry
);
WARN_ON_ONCE
(
ret
);
d_drop
(
dentry
);
fsnotify_rmdir
(
dir
,
dentry
);
dput
(
dentry
);
inode_unlock
(
dir
);
simple_recursive_removal
(
dentry
,
clear_ncl
);
}
static
int
nfsd_fill_super
(
struct
super_block
*
sb
,
struct
fs_context
*
fc
)
...
...
fs/notify/fsnotify.c
View file @
119dcc73
...
...
@@ -124,7 +124,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
* d_flags to indicate parental interest (their parent is the
* original inode) */
spin_lock
(
&
alias
->
d_lock
);
list_for_each_entry
(
child
,
&
alias
->
d_subdirs
,
d_child
)
{
hlist_for_each_entry
(
child
,
&
alias
->
d_children
,
d_sib
)
{
if
(
!
child
->
d_inode
)
continue
;
...
...
fs/tracefs/inode.c
View file @
119dcc73
...
...
@@ -199,26 +199,21 @@ static void change_gid(struct dentry *dentry, kgid_t gid)
*/
static
void
set_gid
(
struct
dentry
*
parent
,
kgid_t
gid
)
{
struct
dentry
*
this_parent
;
struct
list_head
*
next
;
struct
dentry
*
this_parent
,
*
dentry
;
this_parent
=
parent
;
spin_lock
(
&
this_parent
->
d_lock
);
change_gid
(
this_parent
,
gid
);
repeat:
next
=
this_parent
->
d_subdirs
.
next
;
dentry
=
d_first_child
(
this_parent
)
;
resume:
while
(
next
!=
&
this_parent
->
d_subdirs
)
{
struct
list_head
*
tmp
=
next
;
struct
dentry
*
dentry
=
list_entry
(
tmp
,
struct
dentry
,
d_child
);
next
=
tmp
->
next
;
hlist_for_each_entry_from
(
dentry
,
d_sib
)
{
spin_lock_nested
(
&
dentry
->
d_lock
,
DENTRY_D_LOCK_NESTED
);
change_gid
(
dentry
,
gid
);
if
(
!
list_empty
(
&
dentry
->
d_subdirs
))
{
if
(
!
hlist_empty
(
&
dentry
->
d_children
))
{
spin_unlock
(
&
this_parent
->
d_lock
);
spin_release
(
&
dentry
->
d_lock
.
dep_map
,
_RET_IP_
);
this_parent
=
dentry
;
...
...
@@ -233,21 +228,20 @@ static void set_gid(struct dentry *parent, kgid_t gid)
rcu_read_lock
();
ascend:
if
(
this_parent
!=
parent
)
{
struct
dentry
*
child
=
this_parent
;
this_parent
=
child
->
d_parent
;
dentry
=
this_parent
;
this_parent
=
dentry
->
d_parent
;
spin_unlock
(
&
child
->
d_lock
);
spin_unlock
(
&
dentry
->
d_lock
);
spin_lock
(
&
this_parent
->
d_lock
);
/* go into the first sibling still alive */
do
{
next
=
child
->
d_child
.
next
;
if
(
next
==
&
this_parent
->
d_subdirs
)
goto
ascend
;
child
=
list_entry
(
next
,
struct
dentry
,
d_child
);
}
while
(
unlikely
(
child
->
d_flags
&
DCACHE_DENTRY_KILLED
));
rcu_read_unlock
();
goto
resume
;
hlist_for_each_entry_continue
(
dentry
,
d_sib
)
{
if
(
likely
(
!
(
dentry
->
d_flags
&
DCACHE_DENTRY_KILLED
)))
{
rcu_read_unlock
();
goto
resume
;
}
}
goto
ascend
;
}
rcu_read_unlock
();
spin_unlock
(
&
this_parent
->
d_lock
);
...
...
include/linux/dcache.h
View file @
119dcc73
...
...
@@ -68,12 +68,12 @@ extern const struct qstr dotdot_name;
* large memory footprint increase).
*/
#ifdef CONFIG_64BIT
# define DNAME_INLINE_LEN
32
/* 192 bytes */
# define DNAME_INLINE_LEN
40
/* 192 bytes */
#else
# ifdef CONFIG_SMP
# define DNAME_INLINE_LEN 36
/* 128 bytes */
# else
# define DNAME_INLINE_LEN 40
/* 128 bytes */
# else
# define DNAME_INLINE_LEN 44
/* 128 bytes */
# endif
#endif
...
...
@@ -101,8 +101,8 @@ struct dentry {
struct
list_head
d_lru
;
/* LRU list */
wait_queue_head_t
*
d_wait
;
/* in-lookup ones only */
};
struct
list_head
d_child
;
/* child of parent list */
struct
list_head
d_subdirs
;
/* our children */
struct
hlist_node
d_sib
;
/* child of parent list */
struct
hlist_head
d_children
;
/* our children */
/*
* d_alias and d_rcu can share memory
*/
...
...
@@ -564,4 +564,14 @@ struct name_snapshot {
void
take_dentry_name_snapshot
(
struct
name_snapshot
*
,
struct
dentry
*
);
void
release_dentry_name_snapshot
(
struct
name_snapshot
*
);
static
inline
struct
dentry
*
d_first_child
(
const
struct
dentry
*
dentry
)
{
return
hlist_entry_safe
(
dentry
->
d_children
.
first
,
struct
dentry
,
d_sib
);
}
static
inline
struct
dentry
*
d_next_sibling
(
const
struct
dentry
*
dentry
)
{
return
hlist_entry_safe
(
dentry
->
d_sib
.
next
,
struct
dentry
,
d_sib
);
}
#endif
/* __LINUX_DCACHE_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment