When implementing connector fsid cache, we only initialized the cache when the first mark added to object was added by FAN_REPORT_FID group. We forgot to update conn->fsid when the second mark is added by FAN_REPORT_FID group to an already attached connector without fsid cache.
Unified · Split
| @@ -355,6 +355,10 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info) · 354 unmodified lines | ||
| 355 | 355 | /* Mark is just getting destroyed or created? */ |
| 356 | 356 | if (!conn) |
| 357 | 357 | continue; |
| 358 | + if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) | |
| 359 | + continue; | |
| 360 | + /* Pairs with smp_wmb() in fsnotify_add_mark_list() */ | |
| 361 | + smp_rmb(); | |
| 358 | 362 | fsid = conn->fsid; |
| 359 | 363 | if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1])) |
| 360 | 364 | continue; |
| @@ -482,10 +482,13 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, · 481 unmodified lines | ||
| 482 | 482 | conn->type = type; |
| 483 | 483 | conn->obj = connp; |
| 484 | 484 | /* Cache fsid of filesystem containing the object */ |
| 485 | − if (fsid) | |
| 485 | + if (fsid) { | |
| 486 | 486 | conn->fsid = *fsid; |
| 487 | − else | |
| 487 | + conn->flags = FSNOTIFY_CONN_FLAG_HAS_FSID; | |
| 488 | + } else { | |
| 488 | 489 | conn->fsid.val[0] = conn->fsid.val[1] = 0; |
| 490 | + conn->flags = 0; | |
| 491 | + } | |
| 489 | 492 | if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) |
| 490 | 493 | inode = igrab(fsnotify_conn_inode(conn)); |
| 491 | 494 | /* |
| @@ -560,7 +563,12 @@ restart: · 68 unmodified lines | ||
| 560 | 563 | if (err) |
| 561 | 564 | return err; |
| 562 | 565 | goto restart; |
| 563 | − } else if (fsid && (conn->fsid.val[0] || conn->fsid.val[1]) && | |
| 566 | + } else if (fsid && !(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) { | |
| 567 | + conn->fsid = *fsid; | |
| 568 | + /* Pairs with smp_rmb() in fanotify_get_fsid() */ | |
| 569 | + smp_wmb(); | |
| 570 | + conn->flags |= FSNOTIFY_CONN_FLAG_HAS_FSID; | |
| 571 | + } else if (fsid && (conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID) && | |
| 564 | 572 | (fsid->val[0] != conn->fsid.val[0] || |
| 565 | 573 | fsid->val[1] != conn->fsid.val[1])) { |
| 566 | 574 | /* |
| @@ -292,7 +292,9 @@ typedef struct fsnotify_mark_connector __rcu *fsnotify_connp_t; · 291 unmodified lines | ||
| 292 | 292 | */ |
| 293 | 293 | struct fsnotify_mark_connector { |
| 294 | 294 | spinlock_t lock; |
| 295 | − unsigned int type; /* Type of object [lock] */ | |
| 295 | + unsigned short type; /* Type of object [lock] */ | |
| 296 | +#define FSNOTIFY_CONN_FLAG_HAS_FSID 0x01 | |
| 297 | + unsigned short flags; /* flags [lock] */ | |
| 296 | 298 | __kernel_fsid_t fsid; /* fsid of filesystem containing object */ |
| 297 | 299 | union { |
| 298 | 300 | /* Object pointer [lock] */ |