diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-02 13:28:43 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-02 13:28:43 -0500 |
commit | 7e05b807b93cc553bc2aa5ae8fac620cece34720 (patch) | |
tree | 6240b09f201c210d7e3f5cd46086a64852530de2 | |
parent | 4cb8c3593bbb884c5c282b1d8502a0930235fe88 (diff) | |
parent | 9f2f7d4c8dfcf4617af5de6ea381b91deac3db48 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull VFS fixes from Al Viro:
"A bunch of assorted fixes, most of them followups to overlayfs merge"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
ovl: initialize ->is_cursor
Return short read or 0 at end of a raw device, not EIO
isofs: don't bother with ->d_op for normal case
isofs_cmp(): we'll never see a dentry for . or ..
overlayfs: fix lockdep misannotation
ovl: fix check for cursor
overlayfs: barriers for opening upper-layer directory
rcu: Provide counterpart to rcu_dereference() for non-RCU situations
staging: android: logger: Fix log corruption regression
-rw-r--r-- | drivers/char/raw.c | 2 | ||||
-rw-r--r-- | drivers/staging/android/logger.c | 13 | ||||
-rw-r--r-- | fs/block_dev.c | 3 | ||||
-rw-r--r-- | fs/isofs/inode.c | 24 | ||||
-rw-r--r-- | fs/isofs/namei.c | 22 | ||||
-rw-r--r-- | fs/namei.c | 2 | ||||
-rw-r--r-- | fs/overlayfs/readdir.c | 17 | ||||
-rw-r--r-- | include/linux/fs.h | 10 | ||||
-rw-r--r-- | include/linux/rcupdate.h | 15 |
9 files changed, 50 insertions, 58 deletions
diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 0102dc788608..a24891b97547 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c | |||
@@ -285,7 +285,7 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd, | |||
285 | 285 | ||
286 | static const struct file_operations raw_fops = { | 286 | static const struct file_operations raw_fops = { |
287 | .read = new_sync_read, | 287 | .read = new_sync_read, |
288 | .read_iter = generic_file_read_iter, | 288 | .read_iter = blkdev_read_iter, |
289 | .write = new_sync_write, | 289 | .write = new_sync_write, |
290 | .write_iter = blkdev_write_iter, | 290 | .write_iter = blkdev_write_iter, |
291 | .fsync = blkdev_fsync, | 291 | .fsync = blkdev_fsync, |
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c index 28b93d39a94e..a673ffa34aa3 100644 --- a/drivers/staging/android/logger.c +++ b/drivers/staging/android/logger.c | |||
@@ -420,7 +420,7 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
420 | struct logger_log *log = file_get_log(iocb->ki_filp); | 420 | struct logger_log *log = file_get_log(iocb->ki_filp); |
421 | struct logger_entry header; | 421 | struct logger_entry header; |
422 | struct timespec now; | 422 | struct timespec now; |
423 | size_t len, count; | 423 | size_t len, count, w_off; |
424 | 424 | ||
425 | count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD); | 425 | count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD); |
426 | 426 | ||
@@ -452,11 +452,14 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
452 | memcpy(log->buffer + log->w_off, &header, len); | 452 | memcpy(log->buffer + log->w_off, &header, len); |
453 | memcpy(log->buffer, (char *)&header + len, sizeof(header) - len); | 453 | memcpy(log->buffer, (char *)&header + len, sizeof(header) - len); |
454 | 454 | ||
455 | len = min(count, log->size - log->w_off); | 455 | /* Work with a copy until we are ready to commit the whole entry */ |
456 | w_off = logger_offset(log, log->w_off + sizeof(struct logger_entry)); | ||
456 | 457 | ||
457 | if (copy_from_iter(log->buffer + log->w_off, len, from) != len) { | 458 | len = min(count, log->size - w_off); |
459 | |||
460 | if (copy_from_iter(log->buffer + w_off, len, from) != len) { | ||
458 | /* | 461 | /* |
459 | * Note that by not updating w_off, this abandons the | 462 | * Note that by not updating log->w_off, this abandons the |
460 | * portion of the new entry that *was* successfully | 463 | * portion of the new entry that *was* successfully |
461 | * copied, just above. This is intentional to avoid | 464 | * copied, just above. This is intentional to avoid |
462 | * message corruption from missing fragments. | 465 | * message corruption from missing fragments. |
@@ -470,7 +473,7 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
470 | return -EFAULT; | 473 | return -EFAULT; |
471 | } | 474 | } |
472 | 475 | ||
473 | log->w_off = logger_offset(log, log->w_off + count); | 476 | log->w_off = logger_offset(log, w_off + count); |
474 | mutex_unlock(&log->mutex); | 477 | mutex_unlock(&log->mutex); |
475 | 478 | ||
476 | /* wake up any blocked readers */ | 479 | /* wake up any blocked readers */ |
diff --git a/fs/block_dev.c b/fs/block_dev.c index cc9d4114cda0..1d9c9f3754f8 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -1585,7 +1585,7 @@ ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
1585 | } | 1585 | } |
1586 | EXPORT_SYMBOL_GPL(blkdev_write_iter); | 1586 | EXPORT_SYMBOL_GPL(blkdev_write_iter); |
1587 | 1587 | ||
1588 | static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to) | 1588 | ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to) |
1589 | { | 1589 | { |
1590 | struct file *file = iocb->ki_filp; | 1590 | struct file *file = iocb->ki_filp; |
1591 | struct inode *bd_inode = file->f_mapping->host; | 1591 | struct inode *bd_inode = file->f_mapping->host; |
@@ -1599,6 +1599,7 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to) | |||
1599 | iov_iter_truncate(to, size); | 1599 | iov_iter_truncate(to, size); |
1600 | return generic_file_read_iter(iocb, to); | 1600 | return generic_file_read_iter(iocb, to); |
1601 | } | 1601 | } |
1602 | EXPORT_SYMBOL_GPL(blkdev_read_iter); | ||
1602 | 1603 | ||
1603 | /* | 1604 | /* |
1604 | * Try to release a page associated with block device when the system | 1605 | * Try to release a page associated with block device when the system |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 881b3bd0143f..fe839b915116 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
@@ -29,13 +29,9 @@ | |||
29 | #define BEQUIET | 29 | #define BEQUIET |
30 | 30 | ||
31 | static int isofs_hashi(const struct dentry *parent, struct qstr *qstr); | 31 | static int isofs_hashi(const struct dentry *parent, struct qstr *qstr); |
32 | static int isofs_hash(const struct dentry *parent, struct qstr *qstr); | ||
33 | static int isofs_dentry_cmpi(const struct dentry *parent, | 32 | static int isofs_dentry_cmpi(const struct dentry *parent, |
34 | const struct dentry *dentry, | 33 | const struct dentry *dentry, |
35 | unsigned int len, const char *str, const struct qstr *name); | 34 | unsigned int len, const char *str, const struct qstr *name); |
36 | static int isofs_dentry_cmp(const struct dentry *parent, | ||
37 | const struct dentry *dentry, | ||
38 | unsigned int len, const char *str, const struct qstr *name); | ||
39 | 35 | ||
40 | #ifdef CONFIG_JOLIET | 36 | #ifdef CONFIG_JOLIET |
41 | static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr); | 37 | static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr); |
@@ -135,10 +131,6 @@ static const struct super_operations isofs_sops = { | |||
135 | 131 | ||
136 | static const struct dentry_operations isofs_dentry_ops[] = { | 132 | static const struct dentry_operations isofs_dentry_ops[] = { |
137 | { | 133 | { |
138 | .d_hash = isofs_hash, | ||
139 | .d_compare = isofs_dentry_cmp, | ||
140 | }, | ||
141 | { | ||
142 | .d_hash = isofs_hashi, | 134 | .d_hash = isofs_hashi, |
143 | .d_compare = isofs_dentry_cmpi, | 135 | .d_compare = isofs_dentry_cmpi, |
144 | }, | 136 | }, |
@@ -258,25 +250,12 @@ static int isofs_dentry_cmp_common( | |||
258 | } | 250 | } |
259 | 251 | ||
260 | static int | 252 | static int |
261 | isofs_hash(const struct dentry *dentry, struct qstr *qstr) | ||
262 | { | ||
263 | return isofs_hash_common(qstr, 0); | ||
264 | } | ||
265 | |||
266 | static int | ||
267 | isofs_hashi(const struct dentry *dentry, struct qstr *qstr) | 253 | isofs_hashi(const struct dentry *dentry, struct qstr *qstr) |
268 | { | 254 | { |
269 | return isofs_hashi_common(qstr, 0); | 255 | return isofs_hashi_common(qstr, 0); |
270 | } | 256 | } |
271 | 257 | ||
272 | static int | 258 | static int |
273 | isofs_dentry_cmp(const struct dentry *parent, const struct dentry *dentry, | ||
274 | unsigned int len, const char *str, const struct qstr *name) | ||
275 | { | ||
276 | return isofs_dentry_cmp_common(len, str, name, 0, 0); | ||
277 | } | ||
278 | |||
279 | static int | ||
280 | isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry, | 259 | isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry, |
281 | unsigned int len, const char *str, const struct qstr *name) | 260 | unsigned int len, const char *str, const struct qstr *name) |
282 | { | 261 | { |
@@ -930,7 +909,8 @@ root_found: | |||
930 | if (opt.check == 'r') | 909 | if (opt.check == 'r') |
931 | table++; | 910 | table++; |
932 | 911 | ||
933 | s->s_d_op = &isofs_dentry_ops[table]; | 912 | if (table) |
913 | s->s_d_op = &isofs_dentry_ops[table - 1]; | ||
934 | 914 | ||
935 | /* get the root dentry */ | 915 | /* get the root dentry */ |
936 | s->s_root = d_make_root(inode); | 916 | s->s_root = d_make_root(inode); |
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 95295640d9c8..7b543e6b6526 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c | |||
@@ -18,25 +18,10 @@ static int | |||
18 | isofs_cmp(struct dentry *dentry, const char *compare, int dlen) | 18 | isofs_cmp(struct dentry *dentry, const char *compare, int dlen) |
19 | { | 19 | { |
20 | struct qstr qstr; | 20 | struct qstr qstr; |
21 | |||
22 | if (!compare) | ||
23 | return 1; | ||
24 | |||
25 | /* check special "." and ".." files */ | ||
26 | if (dlen == 1) { | ||
27 | /* "." */ | ||
28 | if (compare[0] == 0) { | ||
29 | if (!dentry->d_name.len) | ||
30 | return 0; | ||
31 | compare = "."; | ||
32 | } else if (compare[0] == 1) { | ||
33 | compare = ".."; | ||
34 | dlen = 2; | ||
35 | } | ||
36 | } | ||
37 | |||
38 | qstr.name = compare; | 21 | qstr.name = compare; |
39 | qstr.len = dlen; | 22 | qstr.len = dlen; |
23 | if (likely(!dentry->d_op)) | ||
24 | return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen); | ||
40 | return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr); | 25 | return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr); |
41 | } | 26 | } |
42 | 27 | ||
@@ -146,7 +131,8 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, | |||
146 | (!(de->flags[-sbi->s_high_sierra] & 1))) && | 131 | (!(de->flags[-sbi->s_high_sierra] & 1))) && |
147 | (sbi->s_showassoc || | 132 | (sbi->s_showassoc || |
148 | (!(de->flags[-sbi->s_high_sierra] & 4)))) { | 133 | (!(de->flags[-sbi->s_high_sierra] & 4)))) { |
149 | match = (isofs_cmp(dentry, dpnt, dlen) == 0); | 134 | if (dpnt && (dlen > 1 || dpnt[0] > 1)) |
135 | match = (isofs_cmp(dentry, dpnt, dlen) == 0); | ||
150 | } | 136 | } |
151 | if (match) { | 137 | if (match) { |
152 | isofs_normalize_block_and_offset(de, | 138 | isofs_normalize_block_and_offset(de, |
diff --git a/fs/namei.c b/fs/namei.c index 78512898d3ba..db5fe86319e6 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2497,7 +2497,7 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2) | |||
2497 | } | 2497 | } |
2498 | 2498 | ||
2499 | mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); | 2499 | mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); |
2500 | mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD); | 2500 | mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT2); |
2501 | return NULL; | 2501 | return NULL; |
2502 | } | 2502 | } |
2503 | EXPORT_SYMBOL(lock_rename); | 2503 | EXPORT_SYMBOL(lock_rename); |
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 910553f37aca..4e9d7c1fea52 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c | |||
@@ -21,9 +21,10 @@ struct ovl_cache_entry { | |||
21 | unsigned int len; | 21 | unsigned int len; |
22 | unsigned int type; | 22 | unsigned int type; |
23 | u64 ino; | 23 | u64 ino; |
24 | bool is_whiteout; | ||
25 | struct list_head l_node; | 24 | struct list_head l_node; |
26 | struct rb_node node; | 25 | struct rb_node node; |
26 | bool is_whiteout; | ||
27 | bool is_cursor; | ||
27 | char name[]; | 28 | char name[]; |
28 | }; | 29 | }; |
29 | 30 | ||
@@ -92,6 +93,7 @@ static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len, | |||
92 | p->type = d_type; | 93 | p->type = d_type; |
93 | p->ino = ino; | 94 | p->ino = ino; |
94 | p->is_whiteout = false; | 95 | p->is_whiteout = false; |
96 | p->is_cursor = false; | ||
95 | } | 97 | } |
96 | 98 | ||
97 | return p; | 99 | return p; |
@@ -251,7 +253,7 @@ static int ovl_dir_mark_whiteouts(struct dentry *dir, | |||
251 | 253 | ||
252 | mutex_lock(&dir->d_inode->i_mutex); | 254 | mutex_lock(&dir->d_inode->i_mutex); |
253 | list_for_each_entry(p, rdd->list, l_node) { | 255 | list_for_each_entry(p, rdd->list, l_node) { |
254 | if (!p->name) | 256 | if (p->is_cursor) |
255 | continue; | 257 | continue; |
256 | 258 | ||
257 | if (p->type != DT_CHR) | 259 | if (p->type != DT_CHR) |
@@ -307,7 +309,6 @@ static inline int ovl_dir_read_merged(struct path *upperpath, | |||
307 | } | 309 | } |
308 | out: | 310 | out: |
309 | return err; | 311 | return err; |
310 | |||
311 | } | 312 | } |
312 | 313 | ||
313 | static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) | 314 | static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) |
@@ -316,7 +317,7 @@ static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) | |||
316 | loff_t off = 0; | 317 | loff_t off = 0; |
317 | 318 | ||
318 | list_for_each_entry(p, &od->cache->entries, l_node) { | 319 | list_for_each_entry(p, &od->cache->entries, l_node) { |
319 | if (!p->name) | 320 | if (p->is_cursor) |
320 | continue; | 321 | continue; |
321 | if (off >= pos) | 322 | if (off >= pos) |
322 | break; | 323 | break; |
@@ -389,7 +390,7 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx) | |||
389 | 390 | ||
390 | p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node); | 391 | p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node); |
391 | /* Skip cursors */ | 392 | /* Skip cursors */ |
392 | if (p->name) { | 393 | if (!p->is_cursor) { |
393 | if (!p->is_whiteout) { | 394 | if (!p->is_whiteout) { |
394 | if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) | 395 | if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) |
395 | break; | 396 | break; |
@@ -454,12 +455,13 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, | |||
454 | if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) { | 455 | if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) { |
455 | struct inode *inode = file_inode(file); | 456 | struct inode *inode = file_inode(file); |
456 | 457 | ||
457 | realfile = od->upperfile; | 458 | realfile =lockless_dereference(od->upperfile); |
458 | if (!realfile) { | 459 | if (!realfile) { |
459 | struct path upperpath; | 460 | struct path upperpath; |
460 | 461 | ||
461 | ovl_path_upper(dentry, &upperpath); | 462 | ovl_path_upper(dentry, &upperpath); |
462 | realfile = ovl_path_open(&upperpath, O_RDONLY); | 463 | realfile = ovl_path_open(&upperpath, O_RDONLY); |
464 | smp_mb__before_spinlock(); | ||
463 | mutex_lock(&inode->i_mutex); | 465 | mutex_lock(&inode->i_mutex); |
464 | if (!od->upperfile) { | 466 | if (!od->upperfile) { |
465 | if (IS_ERR(realfile)) { | 467 | if (IS_ERR(realfile)) { |
@@ -518,6 +520,7 @@ static int ovl_dir_open(struct inode *inode, struct file *file) | |||
518 | od->realfile = realfile; | 520 | od->realfile = realfile; |
519 | od->is_real = (type != OVL_PATH_MERGE); | 521 | od->is_real = (type != OVL_PATH_MERGE); |
520 | od->is_upper = (type != OVL_PATH_LOWER); | 522 | od->is_upper = (type != OVL_PATH_LOWER); |
523 | od->cursor.is_cursor = true; | ||
521 | file->private_data = od; | 524 | file->private_data = od; |
522 | 525 | ||
523 | return 0; | 526 | return 0; |
@@ -569,7 +572,7 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list) | |||
569 | { | 572 | { |
570 | struct ovl_cache_entry *p; | 573 | struct ovl_cache_entry *p; |
571 | 574 | ||
572 | mutex_lock_nested(&upper->d_inode->i_mutex, I_MUTEX_PARENT); | 575 | mutex_lock_nested(&upper->d_inode->i_mutex, I_MUTEX_CHILD); |
573 | list_for_each_entry(p, list, l_node) { | 576 | list_for_each_entry(p, list, l_node) { |
574 | struct dentry *dentry; | 577 | struct dentry *dentry; |
575 | 578 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 4e41a4a331bb..9ab779e8a63c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -639,11 +639,13 @@ static inline int inode_unhashed(struct inode *inode) | |||
639 | * 2: child/target | 639 | * 2: child/target |
640 | * 3: xattr | 640 | * 3: xattr |
641 | * 4: second non-directory | 641 | * 4: second non-directory |
642 | * The last is for certain operations (such as rename) which lock two | 642 | * 5: second parent (when locking independent directories in rename) |
643 | * | ||
644 | * I_MUTEX_NONDIR2 is for certain operations (such as rename) which lock two | ||
643 | * non-directories at once. | 645 | * non-directories at once. |
644 | * | 646 | * |
645 | * The locking order between these classes is | 647 | * The locking order between these classes is |
646 | * parent -> child -> normal -> xattr -> second non-directory | 648 | * parent[2] -> child -> grandchild -> normal -> xattr -> second non-directory |
647 | */ | 649 | */ |
648 | enum inode_i_mutex_lock_class | 650 | enum inode_i_mutex_lock_class |
649 | { | 651 | { |
@@ -651,7 +653,8 @@ enum inode_i_mutex_lock_class | |||
651 | I_MUTEX_PARENT, | 653 | I_MUTEX_PARENT, |
652 | I_MUTEX_CHILD, | 654 | I_MUTEX_CHILD, |
653 | I_MUTEX_XATTR, | 655 | I_MUTEX_XATTR, |
654 | I_MUTEX_NONDIR2 | 656 | I_MUTEX_NONDIR2, |
657 | I_MUTEX_PARENT2, | ||
655 | }; | 658 | }; |
656 | 659 | ||
657 | void lock_two_nondirectories(struct inode *, struct inode*); | 660 | void lock_two_nondirectories(struct inode *, struct inode*); |
@@ -2466,6 +2469,7 @@ extern ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, lo | |||
2466 | extern ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); | 2469 | extern ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); |
2467 | 2470 | ||
2468 | /* fs/block_dev.c */ | 2471 | /* fs/block_dev.c */ |
2472 | extern ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to); | ||
2469 | extern ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from); | 2473 | extern ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from); |
2470 | extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, | 2474 | extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, |
2471 | int datasync); | 2475 | int datasync); |
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index a4a819ffb2d1..53ff1a752d7e 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h | |||
@@ -617,6 +617,21 @@ static inline void rcu_preempt_sleep_check(void) | |||
617 | #define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v) | 617 | #define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v) |
618 | 618 | ||
619 | /** | 619 | /** |
620 | * lockless_dereference() - safely load a pointer for later dereference | ||
621 | * @p: The pointer to load | ||
622 | * | ||
623 | * Similar to rcu_dereference(), but for situations where the pointed-to | ||
624 | * object's lifetime is managed by something other than RCU. That | ||
625 | * "something other" might be reference counting or simple immortality. | ||
626 | */ | ||
627 | #define lockless_dereference(p) \ | ||
628 | ({ \ | ||
629 | typeof(p) _________p1 = ACCESS_ONCE(p); \ | ||
630 | smp_read_barrier_depends(); /* Dependency order vs. p above. */ \ | ||
631 | (_________p1); \ | ||
632 | }) | ||
633 | |||
634 | /** | ||
620 | * rcu_assign_pointer() - assign to RCU-protected pointer | 635 | * rcu_assign_pointer() - assign to RCU-protected pointer |
621 | * @p: pointer to assign to | 636 | * @p: pointer to assign to |
622 | * @v: value to assign (publish) | 637 | * @v: value to assign (publish) |